From c30ab7b35a139eccf1c05c82b5b62b0decad3ca5 Mon Sep 17 00:00:00 2001 From: Sylvestre Ledru Date: Fri, 23 Dec 2016 16:36:51 +0100 Subject: [PATCH] New upstream version 1.14.0+dfsg1 --- README.md | 5 +- RELEASES.md | 263 +--- configure | 63 +- mk/cfg/aarch64-unknown-fuchsia.mk | 1 + mk/cfg/wasm32-unknown-emscripten.mk | 24 + mk/cfg/x86_64-unknown-fuchsia.mk | 1 + mk/crates.mk | 19 +- mk/llvm.mk | 32 +- mk/main.mk | 20 +- mk/tests.mk | 3 +- src/bootstrap/Cargo.lock | 180 --- src/bootstrap/Cargo.toml | 9 +- src/bootstrap/README.md | 70 +- src/bootstrap/bin/rustc.rs | 24 +- src/bootstrap/bin/rustdoc.rs | 10 +- src/bootstrap/bootstrap.py | 22 +- src/bootstrap/check.rs | 138 +- src/bootstrap/clean.rs | 59 +- src/bootstrap/compile.rs | 50 +- src/bootstrap/config.rs | 107 +- src/bootstrap/config.toml.example | 9 + src/bootstrap/dist.rs | 71 +- src/bootstrap/doc.rs | 39 +- src/bootstrap/flags.rs | 239 +++- src/bootstrap/install.rs | 61 + src/bootstrap/lib.rs | 316 +---- src/bootstrap/metadata.rs | 95 ++ src/bootstrap/mk/Makefile.in | 35 +- src/bootstrap/native.rs | 27 +- src/bootstrap/sanity.rs | 62 +- src/bootstrap/step.rs | 1180 +++++++++-------- src/bootstrap/util.rs | 21 +- src/build_helper/lib.rs | 8 +- src/compiler-rt/lib/builtins/int_lib.h | 2 +- src/compiler-rt/lib/builtins/powidf2.c | 2 +- src/compiler-rt/lib/builtins/powisf2.c | 2 +- src/doc/book/closures.md | 25 +- src/doc/book/concurrency.md | 6 +- src/doc/book/const-and-static.md | 2 +- src/doc/book/deref-coercions.md | 2 +- src/doc/book/getting-started.md | 77 +- src/doc/book/guessing-game.md | 12 +- src/doc/book/lifetimes.md | 92 +- src/doc/book/references-and-borrowing.md | 4 +- src/doc/book/syntax-index.md | 7 +- src/doc/book/testing.md | 80 +- src/doc/book/type-aliases.md | 2 +- src/doc/book/variable-bindings.md | 2 +- src/doc/footer.inc | 1 - src/doc/grammar.md | 7 + src/doc/reference.md | 56 +- src/doc/rust.css | 8 +- src/etc/local_stage0.sh | 1 + src/liballoc/arc.rs | 433 ++++-- src/liballoc/boxed.rs | 8 +- src/liballoc/lib.rs | 1 - src/liballoc/raw_vec.rs | 15 +- src/liballoc/rc.rs | 62 +- src/liballoc_jemalloc/build.rs | 38 +- src/liballoc_jemalloc/lib.rs | 262 ++-- src/liballoc_system/lib.rs | 14 +- src/libarena/lib.rs | 52 +- src/libcollections/binary_heap.rs | 6 +- src/libcollections/borrow.rs | 83 +- src/libcollections/btree/map.rs | 35 + src/libcollections/btree/set.rs | 5 + src/libcollections/enum_set.rs | 3 - src/libcollections/fmt.rs | 6 +- src/libcollections/lib.rs | 2 +- src/libcollections/linked_list.rs | 1 + src/libcollections/macros.rs | 4 +- src/libcollections/slice.rs | 76 +- src/libcollections/str.rs | 46 +- src/libcollections/string.rs | 39 +- src/libcollections/vec.rs | 475 ++++--- src/libcollections/vec_deque.rs | 82 +- src/libcollectionstest/binary_heap.rs | 4 +- src/libcollectionstest/btree/map.rs | 4 +- src/libcollectionstest/btree/mod.rs | 2 +- src/libcollectionstest/btree/set.rs | 74 +- src/libcollectionstest/cow_str.rs | 141 ++ src/libcollectionstest/lib.rs | 7 +- src/libcollectionstest/slice.rs | 78 +- src/libcollectionstest/str.rs | 15 +- src/libcollectionstest/string.rs | 6 + src/libcollectionstest/vec.rs | 81 +- src/libcollectionstest/vec_deque.rs | 32 +- src/libcompiler_builtins/build.rs | 6 + src/libcompiler_builtins/lib.rs | 4 +- src/libcore/any.rs | 6 +- src/libcore/array.rs | 2 + src/libcore/char.rs | 170 +-- src/libcore/clone.rs | 7 - src/libcore/cmp.rs | 91 +- src/libcore/convert.rs | 6 +- src/libcore/fmt/mod.rs | 30 +- src/libcore/hash/mod.rs | 37 +- src/libcore/hash/sip.rs | 195 ++- src/libcore/internal_macros.rs | 62 + src/libcore/intrinsics.rs | 15 +- src/libcore/iter/iterator.rs | 8 +- src/libcore/iter/mod.rs | 135 +- src/libcore/iter/range.rs | 54 +- src/libcore/iter/traits.rs | 36 +- src/libcore/iter_private.rs | 5 +- src/libcore/lib.rs | 3 + src/libcore/macros.rs | 198 ++- src/libcore/marker.rs | 4 +- src/libcore/mem.rs | 82 ++ src/libcore/num/bignum.rs | 17 +- src/libcore/num/diy_float.rs | 35 +- src/libcore/num/f32.rs | 48 +- src/libcore/num/f64.rs | 48 +- src/libcore/num/mod.rs | 34 +- src/libcore/num/wrapping.rs | 22 +- src/libcore/ops.rs | 189 +-- src/libcore/option.rs | 15 +- src/libcore/prelude/v1.rs | 42 +- src/libcore/ptr.rs | 82 +- src/libcore/result.rs | 58 +- src/libcore/slice.rs | 8 + src/libcore/str/mod.rs | 2 +- src/libcore/sync/atomic.rs | 134 +- src/libcoretest/char.rs | 21 +- src/libcoretest/cmp.rs | 26 + src/libcoretest/hash/sip.rs | 21 + src/libcoretest/iter.rs | 12 + src/libcoretest/lib.rs | 2 + src/libcoretest/num/flt2dec/estimator.rs | 5 + src/libcoretest/result.rs | 6 + src/libflate/lib.rs | 35 +- src/libgetopts/lib.rs | 4 +- src/libgraphviz/lib.rs | 10 +- src/liblibc/.travis.yml | 7 +- src/liblibc/Cargo.lock | 12 +- src/liblibc/Cargo.toml | 2 +- .../mips64-unknown-linux-gnuabi64/Dockerfile | 11 + src/liblibc/ci/run.sh | 4 + src/liblibc/libc-test/Cargo.toml | 5 +- .../libc-test/generate-files/Cargo.toml | 2 +- src/liblibc/src/lib.rs | 3 - src/liblibc/src/unix/mod.rs | 12 +- src/liblibc/src/unix/notbsd/linux/mips64.rs | 6 + src/liblibc/src/unix/notbsd/linux/mod.rs | 3 + src/liblibc/src/unix/notbsd/linux/musl/mod.rs | 2 +- .../src/unix/notbsd/linux/other/mod.rs | 1 + src/liblibc/src/unix/notbsd/mod.rs | 10 +- src/liblog/directive.rs | 57 +- src/libpanic_unwind/Cargo.lock | 27 - src/libpanic_unwind/dwarf/eh.rs | 10 +- src/libpanic_unwind/emcc.rs | 75 ++ src/libpanic_unwind/gcc.rs | 25 +- src/libpanic_unwind/lib.rs | 8 +- src/libpanic_unwind/seh64_gnu.rs | 3 +- src/libproc_macro/Cargo.toml | 4 - src/libproc_macro/lib.rs | 248 ++-- src/libproc_macro_plugin/Cargo.toml | 15 + src/libproc_macro_plugin/lib.rs | 107 ++ .../qquote.rs | 18 +- .../Cargo.toml | 5 +- .../build.rs | 0 src/libproc_macro_tokens/lib.rs | 66 + .../parse.rs | 0 .../prelude.rs | 0 src/librand/chacha.rs | 20 +- src/librand/distributions/mod.rs | 30 +- src/librand/isaac.rs | 32 +- src/librand/rand_impls.rs | 6 +- src/librand/reseeding.rs | 6 +- src/librustc/cfg/construct.rs | 18 +- src/librustc/dep_graph/graph.rs | 19 +- src/librustc/dep_graph/raii.rs | 28 +- src/librustc/dep_graph/shadow.rs | 5 + src/librustc/dep_graph/thread.rs | 19 +- src/librustc/diagnostics.rs | 17 + src/librustc/hir/def.rs | 85 +- src/librustc/hir/intravisit.rs | 8 +- src/librustc/hir/lowering.rs | 121 +- src/librustc/hir/map/def_collector.rs | 118 +- src/librustc/hir/map/definitions.rs | 9 +- src/librustc/hir/map/mod.rs | 4 +- src/librustc/hir/mod.rs | 56 +- src/librustc/hir/pat_util.rs | 11 +- src/librustc/hir/print.rs | 14 +- src/librustc/infer/combine.rs | 5 +- src/librustc/infer/error_reporting.rs | 138 +- src/librustc/infer/freshen.rs | 5 +- src/librustc/infer/higher_ranked/mod.rs | 15 +- src/librustc/infer/mod.rs | 96 +- src/librustc/infer/type_variable.rs | 5 +- src/librustc/lib.rs | 15 +- src/librustc/lint/builtin.rs | 37 +- src/librustc/lint/context.rs | 135 +- src/librustc/lint/mod.rs | 3 +- src/librustc/middle/cstore.rs | 48 +- src/librustc/middle/dead.rs | 17 +- src/librustc/middle/dependency_format.rs | 11 +- src/librustc/middle/effect.rs | 10 +- src/librustc/middle/expr_use_visitor.rs | 68 +- src/librustc/middle/intrinsicck.rs | 2 +- src/librustc/middle/lang_items.rs | 2 +- src/librustc/middle/liveness.rs | 20 +- src/librustc/middle/mem_categorization.rs | 52 +- src/librustc/middle/reachable.rs | 4 +- src/librustc/middle/region.rs | 41 +- src/librustc/middle/stability.rs | 25 +- src/librustc/middle/weak_lang_items.rs | 7 +- src/librustc/mir/cache.rs | 2 +- src/librustc/mir/mir_map.rs | 38 - src/librustc/mir/{repr.rs => mod.rs} | 324 ++--- src/librustc/mir/tcx.rs | 39 +- src/librustc/mir/transform.rs | 21 +- src/librustc/mir/traversal.rs | 2 +- src/librustc/mir/visit.rs | 81 +- src/librustc/session/config.rs | 70 +- src/librustc/session/filesearch.rs | 82 +- src/librustc/session/mod.rs | 96 +- src/librustc/traits/coherence.rs | 14 +- src/librustc/traits/error_reporting.rs | 76 +- src/librustc/traits/fulfill.rs | 6 +- src/librustc/traits/mod.rs | 11 +- src/librustc/traits/project.rs | 27 +- src/librustc/traits/select.rs | 23 +- src/librustc/traits/specialize/mod.rs | 48 +- src/librustc/traits/structural_impls.rs | 27 +- src/librustc/traits/util.rs | 85 +- src/librustc/ty/adjustment.rs | 289 ++-- src/librustc/ty/context.rs | 263 +++- src/librustc/ty/error.rs | 27 - src/librustc/ty/fast_reject.rs | 4 +- src/librustc/ty/flags.rs | 22 +- src/librustc/ty/fold.rs | 30 +- src/librustc/ty/layout.rs | 91 +- src/librustc/ty/maps.rs | 4 + src/librustc/ty/mod.rs | 172 +-- src/librustc/ty/outlives.rs | 22 +- src/librustc/ty/relate.rs | 18 +- src/librustc/ty/structural_impls.rs | 38 +- src/librustc/ty/sty.rs | 31 +- src/librustc/ty/subst.rs | 140 +- src/librustc/ty/util.rs | 62 +- src/librustc/ty/walk.rs | 2 +- src/librustc/ty/wf.rs | 15 +- src/librustc/util/common.rs | 34 + src/librustc/util/ppaux.rs | 37 +- src/librustc_back/lib.rs | 32 +- src/librustc_back/sha2.rs | 679 ---------- src/librustc_back/target/aarch64_apple_ios.rs | 3 +- .../target/aarch64_linux_android.rs | 9 +- .../target/aarch64_unknown_fuchsia.rs | 31 + .../target/aarch64_unknown_linux_gnu.rs | 13 +- src/librustc_back/target/arm_base.rs | 16 + .../target/arm_linux_androideabi.rs | 9 +- .../target/arm_unknown_linux_gnueabi.rs | 3 +- .../target/arm_unknown_linux_gnueabihf.rs | 3 +- .../target/arm_unknown_linux_musleabi.rs | 9 +- .../target/arm_unknown_linux_musleabihf.rs | 9 +- src/librustc_back/target/armv7_apple_ios.rs | 3 +- .../target/armv7_linux_androideabi.rs | 9 +- .../target/armv7_unknown_linux_gnueabihf.rs | 5 +- .../target/armv7_unknown_linux_musleabihf.rs | 9 +- src/librustc_back/target/armv7s_apple_ios.rs | 3 +- .../target/asmjs_unknown_emscripten.rs | 3 +- src/librustc_back/target/dragonfly_base.rs | 4 +- src/librustc_back/target/freebsd_base.rs | 4 +- src/librustc_back/target/fuchsia_base.rs | 39 + src/librustc_back/target/i386_apple_ios.rs | 2 +- src/librustc_back/target/i686_apple_darwin.rs | 2 +- .../target/i686_linux_android.rs | 2 +- .../target/i686_pc_windows_gnu.rs | 2 +- .../target/i686_pc_windows_msvc.rs | 2 +- .../target/i686_unknown_dragonfly.rs | 2 +- .../target/i686_unknown_freebsd.rs | 2 +- .../target/i686_unknown_haiku.rs | 2 +- .../target/i686_unknown_linux_gnu.rs | 2 +- .../target/i686_unknown_linux_musl.rs | 2 +- src/librustc_back/target/le32_unknown_nacl.rs | 8 +- .../target/mips64_unknown_linux_gnuabi64.rs | 6 +- .../target/mips64el_unknown_linux_gnuabi64.rs | 6 +- .../target/mips_unknown_linux_gnu.rs | 6 +- .../target/mips_unknown_linux_musl.rs | 6 +- .../target/mips_unknown_linux_uclibc.rs | 6 +- .../target/mipsel_unknown_linux_gnu.rs | 6 +- .../target/mipsel_unknown_linux_musl.rs | 6 +- .../target/mipsel_unknown_linux_uclibc.rs | 6 +- src/librustc_back/target/mod.rs | 96 +- src/librustc_back/target/netbsd_base.rs | 4 +- src/librustc_back/target/openbsd_base.rs | 4 +- .../target/powerpc64_unknown_linux_gnu.rs | 5 +- .../target/powerpc64le_unknown_linux_gnu.rs | 5 +- .../target/powerpc_unknown_linux_gnu.rs | 5 +- .../target/s390x_unknown_linux_gnu.rs | 2 +- src/librustc_back/target/thumb_base.rs | 58 + .../target/thumbv6m_none_eabi.rs | 36 + .../target/thumbv7em_none_eabi.rs | 40 + .../target/thumbv7em_none_eabihf.rs | 49 + .../target/thumbv7m_none_eabi.rs | 31 + .../target/wasm32_unknown_emscripten.rs | 42 + src/librustc_back/target/windows_base.rs | 20 +- .../target/x86_64_apple_darwin.rs | 2 +- src/librustc_back/target/x86_64_apple_ios.rs | 2 +- .../target/x86_64_pc_windows_gnu.rs | 2 +- .../target/x86_64_pc_windows_msvc.rs | 2 +- .../target/x86_64_rumprun_netbsd.rs | 2 +- .../target/x86_64_sun_solaris.rs | 2 +- .../target/x86_64_unknown_bitrig.rs | 2 +- .../target/x86_64_unknown_dragonfly.rs | 2 +- .../target/x86_64_unknown_freebsd.rs | 2 +- .../target/x86_64_unknown_fuchsia.rs | 30 + .../target/x86_64_unknown_haiku.rs | 2 +- .../target/x86_64_unknown_linux_gnu.rs | 2 +- .../target/x86_64_unknown_linux_musl.rs | 2 +- .../target/x86_64_unknown_netbsd.rs | 2 +- .../target/x86_64_unknown_openbsd.rs | 2 +- src/librustc_borrowck/borrowck/check_loans.rs | 112 +- .../borrowck/gather_loans/gather_moves.rs | 2 +- .../borrowck/gather_loans/move_error.rs | 2 +- .../borrowck/mir/abs_domain.rs | 6 +- .../borrowck/mir/dataflow/graphviz.rs | 6 +- .../borrowck/mir/dataflow/impls.rs | 59 +- .../borrowck/mir/dataflow/mod.rs | 57 +- .../borrowck/mir/dataflow/sanity_check.rs | 44 +- .../borrowck/mir/elaborate_drops.rs | 18 +- .../borrowck/mir/gather_moves.rs | 42 +- src/librustc_borrowck/borrowck/mir/mod.rs | 49 +- src/librustc_borrowck/borrowck/mir/patch.rs | 24 +- src/librustc_borrowck/borrowck/mod.rs | 62 +- src/librustc_borrowck/borrowck/move_data.rs | 2 +- src/librustc_borrowck/lib.rs | 4 +- src/librustc_const_eval/Cargo.toml | 2 + src/librustc_const_eval/_match.rs | 767 +++++++++++ src/librustc_const_eval/check_match.rs | 1145 ++++------------ src/librustc_const_eval/diagnostics.rs | 16 +- src/librustc_const_eval/eval.rs | 66 +- src/librustc_const_eval/lib.rs | 6 +- src/librustc_const_eval/pattern.rs | 614 +++++++++ .../accumulate_vec.rs | 52 + src/librustc_data_structures/array_vec.rs | 106 ++ .../bitslice.rs | 3 +- src/librustc_data_structures/blake2b.rs | 338 +++++ .../control_flow_graph/dominators/mod.rs | 28 +- .../control_flow_graph/dominators/test.rs | 22 +- .../control_flow_graph/iterate/test.rs | 20 +- .../control_flow_graph/mod.rs | 6 +- .../control_flow_graph/reachable/mod.rs | 9 +- .../control_flow_graph/reachable/test.rs | 22 +- .../control_flow_graph/reference.rs | 8 +- .../control_flow_graph/test.rs | 11 +- .../control_flow_graph/transpose.rs | 11 +- src/librustc_data_structures/fmt_wrap.rs | 31 + src/librustc_data_structures/graph/mod.rs | 4 +- .../indexed_set.rs | 5 +- src/librustc_data_structures/indexed_vec.rs | 15 + src/librustc_data_structures/lib.rs | 9 + .../obligation_forest/mod.rs | 82 +- .../snapshot_map/mod.rs | 74 +- src/librustc_data_structures/unify/mod.rs | 14 +- src/librustc_driver/Cargo.toml | 9 +- src/librustc_driver/driver.rs | 204 +-- src/librustc_driver/lib.rs | 98 +- src/librustc_driver/pretty.rs | 319 +++-- src/librustc_driver/target_features.rs | 25 +- src/librustc_driver/test.rs | 98 +- src/librustc_errors/Cargo.toml | 2 +- src/librustc_errors/diagnostic.rs | 202 +++ src/librustc_errors/diagnostic_builder.rs | 196 +++ src/librustc_errors/emitter.rs | 180 ++- src/librustc_errors/lib.rs | 349 +---- src/librustc_errors/lock.rs | 15 +- src/librustc_errors/registry.rs | 2 +- src/librustc_errors/snippet.rs | 6 +- src/librustc_errors/styled_buffer.rs | 7 +- .../calculate_svh/hasher.rs | 88 ++ src/librustc_incremental/calculate_svh/mod.rs | 37 +- .../calculate_svh/svh_visitor.rs | 362 ++++- src/librustc_incremental/ich/fingerprint.rs | 81 ++ src/librustc_incremental/ich/mod.rs | 13 + src/librustc_incremental/lib.rs | 3 +- src/librustc_incremental/persist/data.rs | 5 +- src/librustc_incremental/persist/directory.rs | 28 +- .../persist/dirty_clean.rs | 11 +- src/librustc_incremental/persist/fs.rs | 17 +- src/librustc_incremental/persist/hash.rs | 20 +- src/librustc_incremental/persist/load.rs | 5 +- src/librustc_incremental/persist/preds.rs | 3 +- src/librustc_incremental/persist/save.rs | 11 +- src/librustc_lint/bad_style.rs | 167 ++- src/librustc_lint/builtin.rs | 379 ++++-- src/librustc_lint/lib.rs | 85 +- src/librustc_lint/types.rs | 486 +++---- src/librustc_lint/unused.rs | 107 +- src/librustc_llvm/build.rs | 53 +- src/librustc_llvm/diagnostic.rs | 11 +- src/librustc_llvm/ffi.rs | 685 ++++------ src/librustc_llvm/lib.rs | 100 +- src/librustc_macro/lib.rs | 169 --- src/librustc_metadata/Cargo.toml | 2 +- src/librustc_metadata/astencode.rs | 35 +- src/librustc_metadata/creader.rs | 343 +++-- src/librustc_metadata/cstore.rs | 105 +- .../{csearch.rs => cstore_impl.rs} | 44 +- src/librustc_metadata/decoder.rs | 556 ++++---- src/librustc_metadata/diagnostics.rs | 179 --- src/librustc_metadata/encoder.rs | 369 +++--- src/librustc_metadata/index.rs | 16 +- src/librustc_metadata/index_builder.rs | 10 +- src/librustc_metadata/lib.rs | 25 +- .../{loader.rs => locator.rs} | 309 +++-- src/librustc_metadata/macro_import.rs | 219 --- src/librustc_metadata/schema.rs | 78 +- src/librustc_mir/build/block.rs | 2 +- src/librustc_mir/build/cfg.rs | 2 +- src/librustc_mir/build/expr/as_constant.rs | 2 +- src/librustc_mir/build/expr/as_lvalue.rs | 6 +- src/librustc_mir/build/expr/as_operand.rs | 2 +- src/librustc_mir/build/expr/as_rvalue.rs | 6 +- src/librustc_mir/build/expr/as_temp.rs | 2 +- src/librustc_mir/build/expr/into.rs | 2 +- src/librustc_mir/build/expr/stmt.rs | 10 +- src/librustc_mir/build/into.rs | 2 +- src/librustc_mir/build/matches/mod.rs | 20 +- src/librustc_mir/build/matches/simplify.rs | 2 +- src/librustc_mir/build/matches/test.rs | 6 +- src/librustc_mir/build/matches/util.rs | 2 +- src/librustc_mir/build/misc.rs | 8 +- src/librustc_mir/build/mod.rs | 127 +- src/librustc_mir/build/scope.rs | 37 +- src/librustc_mir/def_use.rs | 62 +- src/librustc_mir/graphviz.rs | 31 +- src/librustc_mir/hair/cx/block.rs | 4 +- src/librustc_mir/hair/cx/expr.rs | 154 +-- src/librustc_mir/hair/cx/mod.rs | 7 +- src/librustc_mir/hair/cx/pattern.rs | 328 ----- src/librustc_mir/hair/mod.rs | 80 +- src/librustc_mir/lib.rs | 2 +- src/librustc_mir/mir_map.rs | 47 +- src/librustc_mir/pretty.rs | 61 +- src/librustc_mir/transform/add_call_guards.rs | 2 +- src/librustc_mir/transform/copy_prop.rs | 69 +- src/librustc_mir/transform/deaggregator.rs | 8 +- src/librustc_mir/transform/dump_mir.rs | 2 +- src/librustc_mir/transform/erase_regions.rs | 2 +- src/librustc_mir/transform/instcombine.rs | 7 +- src/librustc_mir/transform/mod.rs | 2 +- src/librustc_mir/transform/no_landing_pads.rs | 2 +- src/librustc_mir/transform/promote_consts.rs | 83 +- src/librustc_mir/transform/qualify_consts.rs | 281 ++-- .../{simplify_cfg.rs => simplify.rs} | 136 +- .../transform/simplify_branches.rs | 2 +- src/librustc_mir/transform/type_check.rs | 27 +- src/librustc_passes/ast_validation.rs | 10 +- src/librustc_passes/consts.rs | 63 +- src/librustc_passes/hir_stats.rs | 374 ++++++ src/librustc_passes/lib.rs | 3 +- src/librustc_passes/static_recursion.rs | 6 +- src/librustc_plugin/load.rs | 14 +- src/librustc_plugin/registry.rs | 10 +- src/librustc_privacy/lib.rs | 52 +- src/librustc_resolve/build_reduced_graph.rs | 466 +++++-- src/librustc_resolve/check_unused.rs | 10 +- src/librustc_resolve/diagnostics.rs | 247 +++- src/librustc_resolve/lib.rs | 293 ++-- src/librustc_resolve/macros.rs | 361 ++--- src/librustc_resolve/resolve_imports.rs | 23 +- src/librustc_save_analysis/dump_visitor.rs | 79 +- src/librustc_save_analysis/json_dumper.rs | 8 +- src/librustc_save_analysis/lib.rs | 22 +- src/librustc_save_analysis/span_utils.rs | 14 +- src/librustc_trans/abi.rs | 73 +- src/librustc_trans/adt.rs | 61 +- src/librustc_trans/asm.rs | 2 +- src/librustc_trans/assert_module_sources.rs | 2 +- src/librustc_trans/back/link.rs | 22 +- src/librustc_trans/back/linker.rs | 33 +- src/librustc_trans/back/rpath.rs | 2 +- src/librustc_trans/back/symbol_names.rs | 30 +- src/librustc_trans/back/write.rs | 2 +- src/librustc_trans/base.rs | 263 ++-- src/librustc_trans/cabi_aarch64.rs | 70 +- src/librustc_trans/cabi_arm.rs | 31 +- src/librustc_trans/cabi_mips.rs | 68 +- src/librustc_trans/cabi_mips64.rs | 68 +- src/librustc_trans/cabi_powerpc.rs | 61 +- src/librustc_trans/cabi_powerpc64.rs | 63 +- src/librustc_trans/cabi_s390x.rs | 6 +- src/librustc_trans/cabi_x86_64.rs | 59 +- src/librustc_trans/callee.rs | 9 +- src/librustc_trans/cleanup.rs | 8 +- src/librustc_trans/collector.rs | 32 +- src/librustc_trans/common.rs | 28 +- src/librustc_trans/consts.rs | 6 +- src/librustc_trans/context.rs | 72 +- .../debuginfo/create_scope_map.rs | 9 +- src/librustc_trans/debuginfo/metadata.rs | 262 +--- src/librustc_trans/debuginfo/mod.rs | 4 +- src/librustc_trans/glue.rs | 17 +- src/librustc_trans/lib.rs | 4 +- src/librustc_trans/meth.rs | 5 +- src/librustc_trans/mir/analyze.rs | 28 +- src/librustc_trans/mir/block.rs | 22 +- src/librustc_trans/mir/constant.rs | 31 +- src/librustc_trans/mir/lvalue.rs | 25 +- src/librustc_trans/mir/mod.rs | 141 +- src/librustc_trans/mir/operand.rs | 26 +- src/librustc_trans/mir/rvalue.rs | 122 +- src/librustc_trans/mir/statement.rs | 6 +- src/librustc_trans/trans_item.rs | 27 +- src/librustc_typeck/astconv.rs | 130 +- src/librustc_typeck/check/_match.rs | 123 +- src/librustc_typeck/check/assoc.rs | 6 +- src/librustc_typeck/check/autoderef.rs | 110 +- src/librustc_typeck/check/callee.rs | 176 +-- src/librustc_typeck/check/cast.rs | 214 +-- src/librustc_typeck/check/closure.rs | 123 +- src/librustc_typeck/check/coercion.rs | 289 ++-- src/librustc_typeck/check/compare_method.rs | 877 +++++++----- src/librustc_typeck/check/dropck.rs | 203 ++- src/librustc_typeck/check/intrinsic.rs | 122 +- src/librustc_typeck/check/method/confirm.rs | 358 ++--- src/librustc_typeck/check/method/mod.rs | 138 +- src/librustc_typeck/check/method/probe.rs | 465 ++++--- src/librustc_typeck/check/method/suggest.rs | 247 ++-- src/librustc_typeck/check/mod.rs | 429 +++--- src/librustc_typeck/check/regionck.rs | 55 +- src/librustc_typeck/check/wfcheck.rs | 8 +- src/librustc_typeck/check/writeback.rs | 40 +- src/librustc_typeck/check_unused.rs | 11 +- src/librustc_typeck/coherence/mod.rs | 208 +-- src/librustc_typeck/coherence/orphan.rs | 109 +- src/librustc_typeck/coherence/overlap.rs | 80 +- src/librustc_typeck/coherence/unsafety.rs | 71 +- src/librustc_typeck/collect.rs | 46 +- src/librustc_typeck/diagnostics.rs | 148 ++- src/librustc_typeck/lib.rs | 43 +- src/librustc_typeck/variance/README.md | 22 +- src/librustc_unicode/char.rs | 92 +- src/librustc_unicode/u_str.rs | 13 +- src/librustdoc/clean/inline.rs | 59 +- src/librustdoc/clean/mod.rs | 157 +-- src/librustdoc/clean/simplify.rs | 2 +- src/librustdoc/core.rs | 15 +- src/librustdoc/externalfiles.rs | 85 +- src/librustdoc/fold.rs | 4 +- src/librustdoc/html/format.rs | 426 ++++-- src/librustdoc/html/highlight.rs | 13 +- src/librustdoc/html/item_type.rs | 20 +- src/librustdoc/html/layout.rs | 9 - src/librustdoc/html/markdown.rs | 45 +- src/librustdoc/html/render.rs | 124 +- src/librustdoc/html/static/playpen.js | 43 - src/librustdoc/html/static/rustdoc.css | 6 +- src/librustdoc/html/toc.rs | 4 +- src/librustdoc/lib.rs | 13 +- src/librustdoc/markdown.rs | 24 +- src/librustdoc/passes/mod.rs | 2 +- src/librustdoc/test.rs | 58 +- src/librustdoc/visit_ast.rs | 2 +- src/librustdoc/visit_lib.rs | 7 +- src/libserialize/json.rs | 17 +- src/libserialize/leb128.rs | 2 + src/libserialize/opaque.rs | 21 +- src/libserialize/serialize.rs | 5 +- src/libstd/build.rs | 4 +- src/libstd/collections/hash/bench.rs | 6 +- src/libstd/collections/hash/map.rs | 703 ++++++---- src/libstd/collections/hash/set.rs | 282 ++-- src/libstd/collections/hash/table.rs | 242 ++-- src/libstd/collections/mod.rs | 123 +- src/libstd/env.rs | 194 +-- src/libstd/error.rs | 22 +- src/libstd/{num => }/f32.rs | 0 src/libstd/{num => }/f64.rs | 0 src/libstd/ffi/c_str.rs | 4 +- src/libstd/ffi/os_str.rs | 11 - src/libstd/fs.rs | 129 +- src/libstd/io/buffered.rs | 21 +- src/libstd/io/cursor.rs | 55 +- src/libstd/io/error.rs | 78 +- src/libstd/io/impls.rs | 11 + src/libstd/io/mod.rs | 191 +-- src/libstd/io/stdio.rs | 26 +- src/libstd/lib.rs | 152 ++- src/libstd/macros.rs | 28 +- src/libstd/memchr.rs | 275 +--- src/libstd/net/addr.rs | 37 +- src/libstd/net/ip.rs | 37 +- src/libstd/net/mod.rs | 3 +- src/libstd/net/parser.rs | 2 +- src/libstd/net/tcp.rs | 2 +- src/libstd/net/test.rs | 2 + src/libstd/net/udp.rs | 2 +- src/libstd/{num/mod.rs => num.rs} | 0 src/libstd/os/fuchsia/fs.rs | 103 ++ src/libstd/os/fuchsia/mod.rs | 16 + src/libstd/os/fuchsia/raw.rs | 270 ++++ src/libstd/os/linux/raw.rs | 3 +- src/libstd/os/mod.rs | 1 + src/libstd/os/raw.rs | 6 +- src/libstd/panic.rs | 46 +- src/libstd/path.rs | 153 +-- src/libstd/primitive_docs.rs | 2 +- src/libstd/process.rs | 22 +- src/libstd/rand/mod.rs | 3 +- src/libstd/rt.rs | 2 +- src/libstd/sync/barrier.rs | 1 + src/libstd/sync/condvar.rs | 4 + src/libstd/sync/mpsc/mod.rs | 11 +- src/libstd/sync/mpsc/mpsc_queue.rs | 2 +- src/libstd/sync/mpsc/oneshot.rs | 2 + src/libstd/sync/mpsc/select.rs | 4 +- src/libstd/sync/mpsc/spsc_queue.rs | 2 +- src/libstd/sync/mutex.rs | 2 +- src/libstd/sync/once.rs | 16 +- src/libstd/sync/rwlock.rs | 10 +- src/libstd/sys/common/args.rs | 100 -- src/libstd/sys/mod.rs | 41 + src/libstd/sys/unix/android.rs | 63 +- src/libstd/sys/unix/args.rs | 212 +++ src/libstd/sys/unix/env.rs | 184 +++ src/libstd/sys/unix/ext/fs.rs | 45 + src/libstd/sys/unix/ext/mod.rs | 2 + src/libstd/sys/unix/ext/net.rs | 15 +- src/libstd/sys/unix/ext/process.rs | 6 +- src/libstd/sys/unix/fast_thread_local.rs | 167 +++ src/libstd/sys/unix/fd.rs | 54 +- src/libstd/sys/unix/fs.rs | 24 +- src/libstd/sys/unix/memchr.rs | 57 + src/libstd/sys/unix/mod.rs | 23 +- src/libstd/sys/unix/net.rs | 14 +- src/libstd/sys/unix/os.rs | 143 +- src/libstd/sys/unix/path.rs | 29 + src/libstd/sys/unix/process.rs | 4 +- src/libstd/sys/unix/rand.rs | 72 +- src/libstd/sys/unix/stdio.rs | 3 + src/libstd/sys/unix/thread.rs | 49 +- src/libstd/sys/windows/args.rs | 76 ++ src/libstd/sys/windows/env.rs | 19 + src/libstd/sys/windows/ext/fs.rs | 51 +- src/libstd/sys/windows/ext/mod.rs | 2 + src/libstd/sys/windows/ext/process.rs | 10 +- src/libstd/sys/windows/fs.rs | 16 + src/libstd/sys/windows/handle.rs | 30 + src/libstd/sys/windows/memchr.rs | 15 + src/libstd/sys/windows/mod.rs | 24 +- src/libstd/sys/windows/os.rs | 56 - src/libstd/sys/windows/path.rs | 108 ++ src/libstd/sys/windows/stdio.rs | 7 + .../{sys/common => sys_common}/at_exit_imp.rs | 0 .../{sys/common => sys_common}/backtrace.rs | 0 .../{sys/common => sys_common}/condvar.rs | 0 .../common => sys_common}/gnu/libbacktrace.rs | 0 .../{sys/common => sys_common}/gnu/mod.rs | 0 src/libstd/{sys/common => sys_common}/io.rs | 4 + src/libstd/sys_common/memchr.rs | 230 ++++ src/libstd/{sys/common => sys_common}/mod.rs | 34 +- .../{sys/common => sys_common}/mutex.rs | 0 src/libstd/{sys/common => sys_common}/net.rs | 19 +- .../{sys/common => sys_common}/poison.rs | 0 .../{sys/common => sys_common}/remutex.rs | 2 +- .../{sys/common => sys_common}/rwlock.rs | 0 .../{sys/common => sys_common}/thread.rs | 0 .../{sys/common => sys_common}/thread_info.rs | 0 .../common => sys_common}/thread_local.rs | 0 src/libstd/{sys/common => sys_common}/util.rs | 28 +- src/libstd/{sys/common => sys_common}/wtf8.rs | 21 +- src/libstd/thread/local.rs | 153 +-- src/libstd/thread/mod.rs | 74 +- src/libstd/time/mod.rs | 2 +- src/libsyntax/abi.rs | 50 +- src/libsyntax/ast.rs | 26 +- src/libsyntax/attr.rs | 13 +- src/libsyntax/codemap.rs | 6 +- src/libsyntax/config.rs | 24 +- src/libsyntax/diagnostics/plugin.rs | 2 +- src/libsyntax/ext/base.rs | 71 +- src/libsyntax/ext/build.rs | 48 +- src/libsyntax/ext/expand.rs | 142 +- src/libsyntax/ext/hygiene.rs | 5 + src/libsyntax/ext/placeholders.rs | 3 +- src/libsyntax/ext/quote.rs | 124 +- src/libsyntax/ext/source_util.rs | 11 +- src/libsyntax/ext/tt/macro_parser.rs | 92 +- src/libsyntax/ext/tt/macro_rules.rs | 64 +- src/libsyntax/ext/tt/transcribe.rs | 94 +- src/libsyntax/feature_gate.rs | 256 +++- src/libsyntax/fold.rs | 113 +- src/libsyntax/json.rs | 16 +- src/libsyntax/lib.rs | 2 + src/libsyntax/parse/attr.rs | 17 +- src/libsyntax/parse/lexer/comments.rs | 84 +- src/libsyntax/parse/lexer/mod.rs | 415 +++--- src/libsyntax/parse/lexer/unicode_chars.rs | 2 +- src/libsyntax/parse/mod.rs | 178 +-- src/libsyntax/parse/parser.rs | 955 ++++++------- src/libsyntax/parse/token.rs | 78 +- src/libsyntax/print/pp.rs | 69 +- src/libsyntax/print/pprust.rs | 67 +- src/libsyntax/std_inject.rs | 22 +- src/libsyntax/test.rs | 85 +- src/libsyntax/tokenstream.rs | 22 +- src/libsyntax/util/interner.rs | 40 +- src/libsyntax/util/parser_testing.rs | 5 +- src/libsyntax/util/small_vector.rs | 56 +- src/libsyntax/visit.rs | 8 +- src/libsyntax_ext/Cargo.toml | 2 +- src/libsyntax_ext/asm.rs | 18 +- src/libsyntax_ext/cfg.rs | 2 +- src/libsyntax_ext/deriving/cmp/partial_eq.rs | 4 +- src/libsyntax_ext/deriving/cmp/partial_ord.rs | 4 +- src/libsyntax_ext/deriving/custom.rs | 2 +- src/libsyntax_ext/deriving/decodable.rs | 4 +- src/libsyntax_ext/deriving/encodable.rs | 14 +- src/libsyntax_ext/deriving/generic/mod.rs | 10 +- src/libsyntax_ext/deriving/generic/ty.rs | 7 +- src/libsyntax_ext/deriving/mod.rs | 268 ++-- src/libsyntax_ext/format.rs | 2 +- src/libsyntax_ext/lib.rs | 32 +- ...o_registrar.rs => proc_macro_registrar.rs} | 73 +- src/libsyntax_pos/lib.rs | 2 +- src/libtest/lib.rs | 158 ++- src/libunwind/build.rs | 2 + src/libunwind/libunwind.rs | 4 +- src/rtstartup/rsbegin.rs | 6 +- src/rustc/Cargo.lock | 413 ------ src/rustc/std_shim/Cargo.lock | 132 -- src/rustc/test_shim/Cargo.lock | 23 - src/rustllvm/RustWrapper.cpp | 21 +- src/rustllvm/llvm-auto-clean-trigger | 2 +- src/stage0.txt | 4 +- .../item-collection/overloaded-operators.rs | 8 +- src/test/codegen/abi-sysv64.rs | 3 + src/test/codegen/consts.rs | 6 +- src/test/codegen/enum-bounds-check.rs | 24 + src/test/codegen/issue-32364.rs | 3 + src/test/codegen/lifetime_start_end.rs | 8 +- src/test/codegen/zip.rs | 9 + .../auxiliary/macro_crate_test.rs | 4 +- .../derive-no-std-not-supported.rs | 1 - .../dropck_tarena_cycle_checked.rs | 4 +- .../dropck_tarena_unsound_drop.rs | 5 +- src/test/compile-fail-fulldeps/issue-18986.rs | 2 +- .../macro-crate-doesnt-resolve.rs | 3 +- ...nown-crate.rs => no-link-unknown-crate.rs} | 2 +- .../at-the-root.rs | 12 +- .../proc-macro/attribute.rs | 46 + .../auxiliary/derive-a.rs | 12 +- .../auxiliary/derive-bad.rs | 12 +- .../auxiliary/derive-panic.rs | 12 +- .../auxiliary/derive-unstable-2.rs | 12 +- .../auxiliary/derive-unstable.rs | 12 +- .../cannot-link.rs | 2 +- .../{rustc-macro => proc-macro}/define-two.rs | 12 +- .../{rustc-macro => proc-macro}/derive-bad.rs | 2 +- .../derive-still-gated.rs | 2 +- .../expand-to-unstable-2.rs | 2 +- .../expand-to-unstable.rs | 2 +- .../export-macro.rs | 6 +- .../{rustc-macro => proc-macro}/exports.rs | 2 +- .../feature-gate-1.rs | 4 +- .../feature-gate-2.rs | 2 +- .../feature-gate-3.rs | 4 +- .../feature-gate-4.rs | 0 .../feature-gate-5.rs | 2 +- .../illegal-proc-macro-derive-use.rs | 27 + .../{rustc-macro => proc-macro}/import.rs | 2 +- .../{rustc-macro => proc-macro}/load-panic.rs | 2 +- .../shadow-builtin.rs | 10 +- .../{rustc-macro => proc-macro}/shadow.rs | 5 +- .../{rustc-macro => proc-macro}/signature.rs | 10 +- .../two-crate-types-1.rs | 4 +- .../two-crate-types-2.rs | 4 +- src/test/compile-fail-fulldeps/qquote.rs | 2 +- .../rustc-macro/attribute.rs | 46 - .../compile-fail/{E0002.rs => E0004-2.rs} | 2 +- src/test/compile-fail/E0007.rs | 1 + src/test/compile-fail/E0025.rs | 5 +- src/test/compile-fail/E0035.rs | 1 + src/test/compile-fail/E0036.rs | 1 + src/test/compile-fail/E0050.rs | 9 +- src/test/compile-fail/E0071.rs | 9 +- src/test/compile-fail/E0164.rs | 8 +- src/test/compile-fail/E0198.rs | 18 + src/test/compile-fail/E0199.rs | 3 +- src/test/compile-fail/E0220.rs | 5 +- src/test/compile-fail/E0221.rs | 18 +- src/test/compile-fail/E0243.rs | 2 +- src/test/compile-fail/E0277.rs | 2 +- src/test/compile-fail/E0297.rs | 2 +- src/test/compile-fail/E0303.rs | 8 +- src/test/compile-fail/E0408.rs | 4 +- .../compile-fail/allocator-dylib-is-system.rs | 2 + .../allocator-rust-dylib-is-jemalloc.rs | 2 + src/test/compile-fail/associated-path-shl.rs | 20 + ...pe-projection-from-multiple-supertraits.rs | 14 +- ...ed-types-ICE-when-projecting-out-of-err.rs | 2 +- .../attempted-access-non-fatal.rs | 4 +- .../attr-on-generic-formals-are-visited.rs | 75 ++ ...attr-on-generic-formals-wo-feature-gate.rs | 76 ++ .../attrs-with-no-formal-in-generics-1.rs | 26 + .../attrs-with-no-formal-in-generics-2.rs | 26 + .../attrs-with-no-formal-in-generics-3.rs | 26 + .../compile-fail/auto-ref-slice-plus-ref.rs | 2 +- .../compile-fail/auxiliary/define_macro.rs | 16 + .../auxiliary/import_crate_var.rs | 12 + .../auxiliary/namespace-mix-new.rs | 78 ++ .../auxiliary/namespace-mix-old.rs | 85 ++ .../compile-fail/blind-item-block-middle.rs | 2 +- .../borrowck/borrowck-assign-comp-idx.rs | 6 +- .../borrowck-borrowed-uniq-rvalue-2.rs | 2 +- .../borrowck/borrowck-loan-vec-content.rs | 4 +- ...rowck-move-out-of-overloaded-auto-deref.rs | 2 +- .../borrowck/borrowck-move-out-of-vec-tail.rs | 4 +- .../borrowck/borrowck-mut-slice-of-imm-vec.rs | 2 +- ...borrowck-overloaded-index-move-from-vec.rs | 2 +- .../borrowck-use-uninitialized-in-cast.rs | 2 - .../borrowck-vec-pattern-element-loan.rs | 6 +- .../borrowck-vec-pattern-loan-from-mut.rs | 2 +- .../borrowck/borrowck-vec-pattern-nesting.rs | 8 +- .../borrowck-vec-pattern-tail-element-loan.rs | 2 +- src/test/compile-fail/cast-rfc0401.rs | 6 +- src/test/compile-fail/coherence-cow.rs | 2 - .../compile-fail/coherence-vec-local-2.rs | 2 - src/test/compile-fail/coherence-vec-local.rs | 2 - .../compile-fail/const-eval-overflow-2.rs | 4 - .../const-pattern-not-const-evaluable.rs | 4 +- src/test/compile-fail/const-unsized.rs | 8 +- src/test/compile-fail/dep-graph-type-alias.rs | 56 + .../derived-errors/issue-30580.rs | 2 +- .../deriving-meta-unknown-trait.rs | 4 +- src/test/compile-fail/discrim-overflow-2.rs | 32 +- src/test/compile-fail/discrim-overflow.rs | 32 +- .../drop-with-active-borrows-2.rs | 2 +- src/test/compile-fail/empty-comment.rs | 6 +- .../compile-fail/empty-struct-braces-pat-1.rs | 4 +- .../compile-fail/empty-struct-braces-pat-2.rs | 8 +- .../compile-fail/empty-struct-braces-pat-3.rs | 12 +- .../compile-fail/empty-struct-tuple-pat.rs | 10 +- .../compile-fail/empty-struct-unit-pat-1.rs | 51 - .../compile-fail/empty-struct-unit-pat-2.rs | 47 - .../compile-fail/empty-struct-unit-pat.rs | 61 + src/test/compile-fail/enum-in-scope.rs | 2 +- .../compile-fail/enums-are-namespaced-xc.rs | 3 +- .../compile-fail/enums-pats-not-idents.rs | 2 +- .../compile-fail/extern-crate-visibility.rs | 11 +- ...s => feature-gate-field-init-shorthand.rs} | 17 +- .../compile-fail/feature-gate-may-dangle.rs | 20 + .../compile-fail/feature-gate-no-debug-2.rs | 15 + .../compile-fail/gated-non-ascii-idents.rs | 2 +- .../generic-type-less-params-with-defaults.rs | 2 +- .../compile-fail/if-without-else-result.rs | 2 +- .../impl-trait/auto-trait-leak.rs | 8 +- src/test/compile-fail/import-crate-var.rs | 21 + src/test/compile-fail/inherent-overlap.rs | 12 +- src/test/compile-fail/integral-indexing.rs | 2 +- src/test/compile-fail/issue-10200.rs | 2 +- src/test/compile-fail/issue-11004.rs | 4 +- src/test/compile-fail/issue-11873.rs | 2 +- src/test/compile-fail/issue-12612.rs | 2 +- src/test/compile-fail/issue-12863.rs | 2 +- src/test/compile-fail/issue-13352.rs | 2 - src/test/compile-fail/issue-13446.rs | 2 +- src/test/compile-fail/issue-14092.rs | 2 +- src/test/compile-fail/issue-14721.rs | 3 +- src/test/compile-fail/issue-14853.rs | 2 +- src/test/compile-fail/issue-15260.rs | 25 +- src/test/compile-fail/issue-16058.rs | 2 +- src/test/compile-fail/issue-1697.rs | 2 +- src/test/compile-fail/issue-17001.rs | 2 +- src/test/compile-fail/issue-17025.rs | 2 + src/test/compile-fail/issue-17405.rs | 2 +- src/test/compile-fail/issue-17518.rs | 2 +- src/test/compile-fail/issue-17933.rs | 2 +- src/test/compile-fail/issue-18937.rs | 53 + src/test/compile-fail/issue-19086.rs | 2 +- src/test/compile-fail/issue-19244-2.rs | 2 +- src/test/compile-fail/issue-19482.rs | 2 - src/test/compile-fail/issue-21449.rs | 3 +- src/test/compile-fail/issue-21837.rs | 20 + src/test/compile-fail/issue-23253.rs | 2 +- src/test/compile-fail/issue-24363.rs | 2 +- src/test/compile-fail/issue-24365.rs | 6 +- src/test/compile-fail/issue-26158.rs | 16 + src/test/compile-fail/issue-26459.rs | 2 +- src/test/compile-fail/issue-27033.rs | 2 +- src/test/compile-fail/issue-27815.rs | 10 +- src/test/compile-fail/issue-2848.rs | 4 +- src/test/compile-fail/issue-28992-empty.rs | 5 +- src/test/compile-fail/issue-3044.rs | 2 +- src/test/compile-fail/issue-31011.rs | 2 +- src/test/compile-fail/issue-32004.rs | 4 +- src/test/compile-fail/issue-32086.rs | 4 +- src/test/compile-fail/issue-32922.rs | 2 +- src/test/compile-fail/issue-36116.rs | 23 + .../compile-fail/{E0422.rs => issue-36881.rs} | 7 +- src/test/compile-fail/issue-37026.rs | 18 + src/test/compile-fail/issue-37534.rs | 16 + src/test/compile-fail/issue-5067.rs | 2 +- src/test/compile-fail/issue-5883.rs | 2 - src/test/compile-fail/issue-5927.rs | 2 +- src/test/compile-fail/issue-6804.rs | 23 +- src/test/compile-fail/issue-7970a.rs | 6 +- .../issue-pr29383.rs | 6 +- .../keyword-self-as-identifier.rs | 4 +- .../keyword-super-as-identifier.rs | 4 +- .../keyword-super.rs | 4 +- src/test/compile-fail/lexical-scopes.rs | 2 +- src/test/compile-fail/lifetime-underscore.rs | 2 - src/test/compile-fail/lint-group-style.rs | 2 +- .../lint-non-uppercase-statics.rs | 5 +- src/test/compile-fail/lint-qualification.rs | 7 + .../compile-fail/lint-unused-extern-crate.rs | 2 + src/test/compile-fail/lint-unused-imports.rs | 16 +- .../compile-fail/lint-unused-mut-variables.rs | 4 +- src/test/compile-fail/macro-shadowing.rs | 39 + src/test/compile-fail/macro-use-scope.rs | 6 +- .../compile-fail/match-byte-array-patterns.rs | 73 + .../match-pattern-field-mismatch-2.rs | 2 +- .../match-pattern-field-mismatch.rs | 2 +- .../compile-fail/match-vec-unreachable.rs | 2 +- .../meta-expected-error-correct-rev.rs | 1 - .../meta-expected-error-wrong-rev.rs | 1 - .../compile-fail/method-path-in-pattern.rs | 6 +- .../method-resolvable-path-in-pattern.rs | 2 +- .../moves-based-on-type-access-to-field.rs | 2 +- .../compile-fail/moves-based-on-type-exprs.rs | 10 +- src/test/compile-fail/name-clash-nullary.rs | 2 +- src/test/compile-fail/namespace-mix-new.rs | 167 +++ src/test/compile-fail/namespace-mix-old.rs | 174 +++ src/test/compile-fail/no-capture-arc.rs | 2 +- src/test/compile-fail/no-link.rs | 2 +- .../compile-fail/no-patterns-in-args-2.rs | 23 + src/test/compile-fail/no-reuse-move-arc.rs | 2 +- src/test/compile-fail/no-type-for-node-ice.rs | 2 +- src/test/compile-fail/non-copyable-void.rs | 2 +- src/test/compile-fail/non-exhaustive-match.rs | 8 +- ...ct-lifetime-default-from-rptr-box-error.rs | 2 - ...lifetime-default-from-rptr-struct-error.rs | 2 - .../on-unimplemented/multiple-impls.rs | 6 +- .../compile-fail/on-unimplemented/on-impl.rs | 9 +- .../compile-fail/on-unimplemented/on-trait.rs | 6 +- .../on-unimplemented/slice-index.rs | 14 +- .../out-of-order-shadowing.rs} | 14 +- .../pat-shadow-in-nested-binding.rs | 2 +- src/test/compile-fail/pat-tuple-bad-type.rs | 2 - src/test/compile-fail/pat-tuple-overfield.rs | 6 +- .../compile-fail/pattern-error-continue.rs | 2 +- .../compile-fail/qualified-path-params.rs | 2 +- .../regions-bound-missing-bound-in-impl.rs | 2 +- .../resolve-inconsistent-names.rs | 6 +- .../compile-fail/self-vs-path-ambiguity.rs | 23 + src/test/compile-fail/self_type_keyword-2.rs | 12 +- src/test/compile-fail/self_type_keyword.rs | 25 +- .../struct-fields-shorthand-unresolved.rs | 24 + .../compile-fail/struct-fields-shorthand.rs | 24 + src/test/compile-fail/struct-fields-typo.rs | 4 +- .../compile-fail/struct-pat-derived-error.rs | 2 +- .../compile-fail/struct-path-alias-bounds.rs | 21 + .../struct-path-associated-type.rs | 50 + .../struct-path-self-feature-gate.rs | 29 + .../struct-path-self-type-mismatch.rs | 40 + src/test/compile-fail/struct-path-self.rs | 49 + .../trait-as-struct-constructor.rs | 3 +- .../trait-suggest-where-clause.rs | 14 +- .../typeck_type_placeholder_lifetime_1.rs | 2 +- .../typeck_type_placeholder_lifetime_2.rs | 2 +- .../unboxed-closure-sugar-wrong-trait.rs | 3 +- .../unboxed-closures-failed-recursive-fn-2.rs | 2 +- ...es-move-upvar-from-non-once-ref-closure.rs | 2 +- .../compile-fail/union/union-suggest-field.rs | 4 +- src/test/compile-fail/unresolved-import.rs | 2 +- src/test/compile-fail/unsafe-fn-autoderef.rs | 2 +- src/test/compile-fail/unsized-enum.rs | 7 - src/test/compile-fail/unsized-enum2.rs | 68 + src/test/compile-fail/unsized3.rs | 17 +- .../compile-fail/use-super-global-path.rs | 10 +- src/test/compile-fail/variadic-ffi-2.rs | 2 +- src/test/compile-fail/variadic-ffi.rs | 2 +- .../compile-fail/variance-trait-matching.rs | 2 - .../compile-fail/vec-macro-with-comma-only.rs | 2 +- src/test/compile-fail/vec-mut-iter-borrow.rs | 2 +- src/test/compile-fail/vec-res-add.rs | 4 +- .../compile-fail/windows-subsystem-gated.rs | 14 + .../compile-fail/windows-subsystem-invalid.rs | 16 + .../compile-fail/writing-to-immutable-vec.rs | 2 +- .../compile-fail/xcrate-private-by-default.rs | 2 +- src/test/debuginfo/associated-types.rs | 6 +- .../debuginfo/basic-types-globals-metadata.rs | 42 +- src/test/debuginfo/basic-types-globals.rs | 45 +- src/test/debuginfo/basic-types-metadata.rs | 31 +- src/test/debuginfo/basic-types-mut-globals.rs | 90 +- src/test/debuginfo/basic-types.rs | 3 +- src/test/debuginfo/borrowed-basic.rs | 9 +- src/test/debuginfo/borrowed-c-style-enum.rs | 9 +- src/test/debuginfo/borrowed-enum.rs | 9 +- src/test/debuginfo/borrowed-struct.rs | 9 +- src/test/debuginfo/borrowed-tuple.rs | 9 +- src/test/debuginfo/borrowed-unique-basic.rs | 3 +- src/test/debuginfo/box.rs | 3 +- src/test/debuginfo/boxed-struct.rs | 6 +- .../by-value-non-immediate-argument.rs | 15 +- .../by-value-self-argument-in-trait-impl.rs | 6 +- .../debuginfo/c-style-enum-in-composite.rs | 22 +- src/test/debuginfo/c-style-enum.rs | 74 +- src/test/debuginfo/cross-crate-spans.rs | 6 +- .../debuginfo/destructured-fn-argument.rs | 24 +- .../destructured-for-loop-variable.rs | 6 +- src/test/debuginfo/destructured-local.rs | 24 +- src/test/debuginfo/drop-locations.rs | 91 ++ src/test/debuginfo/evec-in-struct.rs | 15 +- src/test/debuginfo/extern-c-fn.rs | 3 +- .../debuginfo/function-arg-initialization.rs | 8 +- ...gdb-pretty-struct-and-enums-pre-gdb-7-7.rs | 9 +- .../generic-enum-with-different-disr-sizes.rs | 31 +- src/test/debuginfo/generic-function.rs | 14 +- .../generic-method-on-generic-struct.rs | 15 +- .../debuginfo/generic-struct-style-enum.rs | 12 +- src/test/debuginfo/generic-struct.rs | 12 +- .../debuginfo/generic-tuple-style-enum.rs | 12 +- src/test/debuginfo/issue14411.rs | 2 +- .../lexical-scopes-in-block-expression.rs | 27 +- src/test/debuginfo/method-on-enum.rs | 15 +- .../debuginfo/method-on-generic-struct.rs | 15 +- src/test/debuginfo/method-on-struct.rs | 15 +- src/test/debuginfo/method-on-trait.rs | 15 +- src/test/debuginfo/method-on-tuple-struct.rs | 15 +- src/test/debuginfo/nil-enum.rs | 9 +- src/test/debuginfo/option-like-enum.rs | 24 +- .../packed-struct-with-destructor.rs | 24 +- src/test/debuginfo/packed-struct.rs | 12 +- src/test/debuginfo/pretty-std.rs | 3 +- src/test/debuginfo/recursive-struct.rs | 43 +- src/test/debuginfo/self-in-default-method.rs | 15 +- .../self-in-generic-default-method.rs | 15 +- src/test/debuginfo/simd.rs | 56 +- src/test/debuginfo/simple-struct.rs | 115 +- src/test/debuginfo/simple-tuple.rs | 121 +- src/test/debuginfo/struct-in-enum.rs | 9 +- src/test/debuginfo/struct-in-struct.rs | 9 +- src/test/debuginfo/struct-style-enum.rs | 12 +- src/test/debuginfo/struct-with-destructor.rs | 14 +- src/test/debuginfo/tuple-in-struct.rs | 30 +- src/test/debuginfo/tuple-in-tuple.rs | 21 +- src/test/debuginfo/tuple-struct.rs | 18 +- src/test/debuginfo/tuple-style-enum.rs | 12 +- src/test/debuginfo/type-names.rs | 138 +- src/test/debuginfo/union-smoke.rs | 6 +- src/test/debuginfo/unique-enum.rs | 9 +- .../var-captured-in-nested-closure.rs | 12 +- .../var-captured-in-sendable-closure.rs | 3 +- .../var-captured-in-stack-closure.rs | 12 +- src/test/debuginfo/vec-slices.rs | 45 +- src/test/debuginfo/vec.rs | 6 +- .../change_crate_order/auxiliary/a.rs} | 11 +- .../change_crate_order/auxiliary/b.rs | 14 + .../incremental/change_crate_order/main.rs | 34 + .../change_private_fn/struct_point.rs | 111 ++ .../change_private_fn_cc/auxiliary/point.rs | 35 + .../change_private_fn_cc/struct_point.rs | 86 ++ .../struct_point.rs | 114 ++ .../auxiliary/point.rs | 35 + .../struct_point.rs | 89 ++ src/test/incremental/hashes/consts.rs | 132 ++ src/test/incremental/hashes/enum_defs.rs | 715 ++++++++++ .../incremental/hashes/function_interfaces.rs | 400 ++++++ src/test/incremental/hashes/panic_exprs.rs | 173 +++ .../hashes/panic_exprs_no_overflow_checks.rs | 251 ++++ src/test/incremental/hashes/statics.rs | 185 +++ src/test/incremental/hashes/struct_defs.rs | 71 + src/test/incremental/hashes/trait_defs.rs | 1115 ++++++++++++++++ .../incremental/struct_change_field_name.rs | 4 +- src/test/mir-opt/deaggregator_test.rs | 22 +- src/test/mir-opt/deaggregator_test_enum.rs | 20 +- src/test/mir-opt/simplify_if.rs | 6 +- src/test/mir-opt/storage_ranges.rs | 40 +- ...ciated-types-project-from-hrtb-explicit.rs | 2 +- .../generic-non-trailing-defaults.rs | 2 +- src/test/parse-fail/issue-10412.rs | 2 +- src/test/parse-fail/issue-17904.rs | 2 +- src/test/parse-fail/issue-37113.rs | 21 + src/test/parse-fail/lex-bad-octal-literal.rs | 2 + src/test/parse-fail/lifetime-no-keyword.rs | 2 +- .../parse-fail/raw-byte-string-literals.rs | 6 +- src/test/parse-fail/recover-enum.rs | 19 + src/test/parse-fail/recover-enum2.rs | 43 + src/test/parse-fail/recover-struct.rs | 19 + .../parse-fail/removed-syntax-field-let.rs | 2 +- src/test/parse-fail/removed-syntax-with-2.rs | 2 +- .../struct-field-numeric-shorthand.rs | 19 + src/test/parse-fail/syntax-trait-polarity.rs | 2 +- .../parse-fail/trailing-plus-in-bounds.rs | 2 +- .../parse-fail/trait-bounds-not-on-impl.rs | 2 +- .../use-as-where-use-ends-with-mod-sep.rs | 2 +- .../where-clauses-no-bounds-or-predicates.rs | 2 +- src/test/pretty/block-disambig.rs | 4 +- src/test/pretty/for-comment.rs | 1 - src/test/pretty/issue-4264.pp | 2 +- src/test/run-fail-fulldeps/qquote.rs | 2 +- src/test/run-fail/divide-by-zero.rs | 2 - src/test/run-fail/glob-use-std.rs | 4 - src/test/run-fail/mod-zero.rs | 2 - src/test/run-fail/overflowing-add.rs | 3 - src/test/run-fail/overflowing-lsh-1.rs | 2 - src/test/run-fail/overflowing-lsh-2.rs | 2 - src/test/run-fail/overflowing-lsh-3.rs | 2 - src/test/run-fail/overflowing-lsh-4.rs | 2 - src/test/run-fail/overflowing-mul.rs | 2 - src/test/run-fail/overflowing-neg.rs | 2 - src/test/run-fail/overflowing-rsh-1.rs | 2 - src/test/run-fail/overflowing-rsh-2.rs | 2 - src/test/run-fail/overflowing-rsh-3.rs | 2 - src/test/run-fail/overflowing-rsh-4.rs | 2 - src/test/run-fail/overflowing-rsh-5.rs | 2 - src/test/run-fail/overflowing-rsh-6.rs | 2 - src/test/run-fail/overflowing-sub.rs | 2 - src/test/run-fail/panic-task-name-none.rs | 1 + src/test/run-fail/panic-task-name-owned.rs | 1 + src/test/run-fail/run-unexported-tests.rs | 1 - src/test/run-fail/task-spawn-barefn.rs | 1 + src/test/run-fail/test-panic.rs | 2 +- .../run-fail/test-should-fail-bad-message.rs | 2 +- src/test/run-fail/test-tasks-invalid-value.rs | 2 +- src/test/run-make/dep-info-spaces/Makefile | 7 +- .../run-make/dep-info-spaces/Makefile.foo | 4 +- src/test/run-make/issue-19371/foo.rs | 10 +- src/test/run-make/llvm-phase/test.rs | 9 +- .../run-make/rustc-macro-dep-files/Makefile | 6 + .../run-make/rustc-macro-dep-files/bar.rs | 21 + .../run-make/rustc-macro-dep-files/foo.rs | 24 + src/test/run-make/save-analysis/foo.rs | 1 - .../run-make/stable-symbol-names/Makefile | 14 +- .../stable-symbol-names1.rs | 14 + .../stable-symbol-names2.rs | 6 + .../run-make/symbols-are-reasonable/Makefile | 8 +- .../run-make/target-without-atomics/Makefile | 5 + src/test/run-make/tools.mk | 3 - src/test/run-make/windows-subsystem/Makefile | 5 + .../run-make/windows-subsystem/console.rs | 15 + .../run-make/windows-subsystem/windows.rs | 14 + .../run-pass-fulldeps/ast_stmt_expr_attr.rs | 5 +- .../auxiliary/cond_noprelude_plugin.rs | 6 +- .../auxiliary/cond_plugin.rs | 6 +- .../auxiliary/cond_prelude_plugin.rs | 6 +- .../auxiliary/custom_derive_partial_eq.rs | 4 +- .../auxiliary/custom_derive_plugin_attr.rs | 1 - .../auxiliary/dummy_mir_pass.rs | 2 +- .../auxiliary/macro_crate_test.rs | 3 +- .../auxiliary/proc_macro_def.rs | 4 +- .../auxiliary/procedural_mbe_matching.rs | 63 +- src/test/run-pass-fulldeps/compiler-calls.rs | 3 +- .../custom-derive-partial-eq.rs | 2 - src/test/run-pass-fulldeps/issue-16992.rs | 1 - .../issue-18763-quote-token-tree.rs | 2 - .../run-pass-fulldeps/lint-group-plugin.rs | 2 - .../lint-plugin-cmdline-load.rs | 1 - src/test/run-pass-fulldeps/lint-plugin.rs | 2 - src/test/run-pass-fulldeps/macro-crate.rs | 2 +- src/test/run-pass-fulldeps/macro-quote-1.rs | 6 +- .../{rustc-macro => proc-macro}/add-impl.rs | 2 +- .../proc-macro}/append-impl.rs | 3 +- .../auxiliary/add-impl.rs | 14 +- .../proc-macro}/auxiliary/append-impl.rs | 12 +- .../auxiliary/derive-a.rs | 16 +- .../auxiliary/derive-atob.rs | 14 +- .../auxiliary/derive-ctod.rs | 12 +- .../auxiliary/derive-same-struct.rs | 14 +- .../auxiliary/expand-with-a-macro.rs | 12 +- .../derive-same-struct.rs | 2 +- .../expand-with-a-macro.rs | 2 +- .../{rustc-macro => proc-macro}/load-two.rs | 3 +- .../{rustc-macro => proc-macro}/smoke.rs | 2 +- src/test/run-pass-fulldeps/qquote.rs | 2 +- src/test/run-pass-fulldeps/quote-tokens.rs | 2 - .../quote-unused-sp-no-warning.rs | 2 - .../run-pass-valgrind/cast-enum-with-dtor.rs | 2 - src/test/run-pass/allocator-override.rs | 1 + src/test/run-pass/assignability-trait.rs | 2 +- ...ciated-types-doubleendediterator-object.rs | 2 +- .../associated-types-iterator-binding.rs | 2 +- src/test/run-pass/attr-on-generic-formals.rs | 60 + src/test/run-pass/auto-loop.rs | 2 +- src/test/run-pass/auto-ref-sliceable.rs | 2 +- src/test/run-pass/autobind.rs | 2 +- .../check_static_recursion_foreign_helper.rs | 4 +- .../auxiliary/dropck_eyepatch_extern_crate.rs | 61 + src/test/run-pass/auxiliary/issue-36954.rs | 18 + src/test/run-pass/backtrace-debuginfo.rs | 2 +- src/test/run-pass/backtrace.rs | 1 - src/test/run-pass/block-arg.rs | 2 +- .../run-pass/borrow-by-val-method-receiver.rs | 2 +- .../borrowck/borrowck-binding-mutbl.rs | 2 +- .../borrowck/borrowck-mut-vec-as-imm-slice.rs | 2 +- .../run-pass/borrowck/borrowck-pat-enum.rs | 2 +- src/test/run-pass/break.rs | 2 +- .../run-pass/by-value-self-in-mut-slot.rs | 2 +- src/test/run-pass/byte-literals.rs | 2 +- src/test/run-pass/cci_no_inline_exe.rs | 2 +- src/test/run-pass/cfg-in-crate-1.rs | 2 - .../class-poly-methods-cross-crate.rs | 8 +- src/test/run-pass/class-poly-methods.rs | 8 +- ...nup-rvalue-temp-during-incomplete-alloc.rs | 2 +- .../run-pass/coerce-reborrow-imm-vec-rcvr.rs | 2 +- .../run-pass/coerce-reborrow-mut-vec-arg.rs | 2 +- .../run-pass/coerce-reborrow-mut-vec-rcvr.rs | 2 +- src/test/run-pass/command-exec.rs | 3 +- src/test/run-pass/const-err.rs | 4 + src/test/run-pass/core-run-destroy.rs | 1 - src/test/run-pass/cstring-drop.rs | 49 - .../run-pass/deprecated-macro_escape-inner.rs | 2 - src/test/run-pass/deprecated-macro_escape.rs | 2 - .../run-pass/deriving-cmp-generic-enum.rs | 3 - src/test/run-pass/deriving-in-macro.rs | 2 +- .../deriving-meta-empty-trait-list.rs | 2 - src/test/run-pass/deriving-show.rs | 3 + .../run-pass/discriminant_value-wrapper.rs | 28 + .../run-pass/drop-with-type-ascription-2.rs | 2 +- .../run-pass/dropck-eyepatch-extern-crate.rs | 48 + src/test/run-pass/dropck-eyepatch-reorder.rs | 89 ++ src/test/run-pass/dropck-eyepatch.rs | 112 ++ src/test/run-pass/enum-size-variance.rs | 2 - src/test/run-pass/expr-fn.rs | 2 +- src/test/run-pass/expr-match-panic.rs | 2 +- src/test/run-pass/extern-methods.rs | 3 + src/test/run-pass/extern-pass-empty.rs | 1 + src/test/run-pass/extern-vectorcall.rs | 3 + src/test/run-pass/for-destruct.rs | 2 +- src/test/run-pass/foreach-nested.rs | 2 +- src/test/run-pass/format-no-std.rs | 2 + src/test/run-pass/generic-ivec-leak.rs | 2 +- src/test/run-pass/generic-static-methods.rs | 2 +- src/test/run-pass/getopts_ref.rs | 2 +- src/test/run-pass/hashmap-memory.rs | 2 +- src/test/run-pass/html-literals.rs | 2 +- src/test/run-pass/hygiene.rs | 14 +- src/test/run-pass/hygienic-labels-in-let.rs | 2 - src/test/run-pass/ifmt.rs | 4 +- src/test/run-pass/import-glob-crate.rs | 12 +- src/test/run-pass/imports.rs | 2 - src/test/run-pass/issue-11709.rs | 2 +- src/test/run-pass/issue-13204.rs | 2 +- src/test/run-pass/issue-14936.rs | 2 +- src/test/run-pass/issue-15080.rs | 2 +- src/test/run-pass/issue-15189.rs | 4 +- src/test/run-pass/issue-15734.rs | 2 +- src/test/run-pass/issue-16492.rs | 2 - src/test/run-pass/issue-16597-empty.rs | 1 - src/test/run-pass/issue-16597.rs | 1 - src/test/run-pass/issue-16668.rs | 2 - src/test/run-pass/issue-18060.rs | 17 + src/test/run-pass/issue-18088.rs | 17 + src/test/run-pass/issue-18464.rs | 2 - src/test/run-pass/issue-18937-1.rs | 30 + src/test/run-pass/issue-20427.rs | 2 +- src/test/run-pass/issue-20823.rs | 1 - src/test/run-pass/issue-22546.rs | 6 + src/test/run-pass/issue-22992.rs | 2 +- .../issue-23338-ensure-param-drop-order.rs | 2 +- src/test/run-pass/issue-2631-b.rs | 2 +- src/test/run-pass/issue-26873-multifile.rs | 5 +- src/test/run-pass/issue-2723-b.rs | 2 +- .../run-pass/issue-27401-dropflag-reinit.rs | 2 +- src/test/run-pass/issue-27639.rs | 2 - src/test/run-pass/issue-28839.rs | 2 +- src/test/run-pass/issue-28936.rs | 2 +- src/test/run-pass/issue-29740.rs | 2 - src/test/run-pass/issue-2989.rs | 4 +- src/test/run-pass/issue-3389.rs | 4 +- src/test/run-pass/issue-34932.rs | 2 - src/test/run-pass/issue-36768.rs | 18 + src/test/run-pass/issue-36786-resolve-call.rs | 17 + src/test/run-pass/issue-36816.rs | 16 + src/test/run-pass/issue-36954.rs | 17 + src/test/run-pass/issue-37175.rs | 14 + src/test/run-pass/issue-37686.rs | 16 + src/test/run-pass/issue-38002.rs | 45 + src/test/run-pass/issue-38033.rs | 88 ++ src/test/run-pass/issue-6153.rs | 2 +- src/test/run-pass/issue-7911.rs | 2 - src/test/run-pass/issue-8460.rs | 2 - src/test/run-pass/issue-9129.rs | 2 +- src/test/run-pass/iter-step-overflow-debug.rs | 29 + .../run-pass/iter-step-overflow-ndebug.rs | 21 + src/test/run-pass/iter-zip.rs | 112 ++ src/test/run-pass/ivec-pass-by-value.rs | 2 +- src/test/run-pass/ivec-tag.rs | 4 +- src/test/run-pass/lambda-infer-unresolved.rs | 2 +- ...line-endings-string-literal-doc-comment.rs | 2 +- src/test/run-pass/linear-for-loop.rs | 4 +- src/test/run-pass/log-poly.rs | 2 +- src/test/run-pass/loop-scope.rs | 2 +- src/test/run-pass/macro-2.rs | 2 - .../run-pass/macro-attribute-expansion.rs | 2 - src/test/run-pass/macro-attributes.rs | 2 - src/test/run-pass/macro-include-items.rs | 2 +- src/test/run-pass/macro-meta-items.rs | 1 - src/test/run-pass/macro-multiple-items.rs | 2 - src/test/run-pass/macro-stmt.rs | 2 - .../run-pass/match-byte-array-patterns.rs | 54 + src/test/run-pass/match-vec-rvalue.rs | 2 +- src/test/run-pass/mir_raw_fat_ptr.rs | 2 - src/test/run-pass/mod_dir_implicit.rs | 2 +- src/test/run-pass/mod_dir_path.rs | 13 +- src/test/run-pass/mod_dir_path2.rs | 2 +- src/test/run-pass/mod_dir_path3.rs | 2 +- src/test/run-pass/mod_dir_path_multi.rs | 2 +- src/test/run-pass/mod_dir_recursive.rs | 2 +- src/test/run-pass/mod_dir_simple.rs | 2 +- src/test/run-pass/mod_file.rs | 2 +- src/test/run-pass/mod_file_with_path_attr.rs | 2 +- src/test/run-pass/monad.rs | 6 +- src/test/run-pass/move-arg-2-unique.rs | 4 +- src/test/run-pass/move-arg-2.rs | 4 +- src/test/run-pass/newtype-polymorphic.rs | 2 +- src/test/run-pass/nonzero-enum.rs | 39 + .../nullable-pointer-iotareduction.rs | 2 +- .../run-pass/numeric-method-autoexport.rs | 2 - ...owned-object-borrowed-method-headerless.rs | 4 +- src/test/run-pass/overloaded-deref.rs | 2 +- src/test/run-pass/packed-struct-layout.rs | 1 + .../run-pass/packed-tuple-struct-layout.rs | 1 + .../abort-link-to-unwinding-crates.rs | 1 + src/test/run-pass/panic-runtime/abort.rs | 1 + src/test/run-pass/panic-runtime/lto-abort.rs | 1 + src/test/run-pass/panic-runtime/lto-unwind.rs | 1 + src/test/run-pass/pat-tuple-1.rs | 2 - src/test/run-pass/pat-tuple-2.rs | 2 - src/test/run-pass/pat-tuple-3.rs | 2 - src/test/run-pass/pat-tuple-4.rs | 2 - src/test/run-pass/pat-tuple-5.rs | 2 - src/test/run-pass/pat-tuple-6.rs | 2 - .../run-pass/process-status-inherits-stdin.rs | 1 + .../run-pass/project-cache-issue-37154.rs | 28 + src/test/run-pass/range_inclusive.rs | 2 +- src/test/run-pass/rcvr-borrowed-to-slice.rs | 6 +- .../run-pass/reexport-test-harness-main.rs | 1 - src/test/run-pass/regions-borrow-evec-uniq.rs | 4 +- .../regions-bound-lists-feature-gate-2.rs | 2 - .../regions-bound-lists-feature-gate.rs | 2 - .../run-pass/regions-dependent-addr-of.rs | 2 +- .../run-pass/regions-dependent-autoslice.rs | 2 +- .../regions-infer-borrow-scope-view.rs | 2 +- ...ions-on-closures-to-inference-variables.rs | 2 +- src/test/run-pass/seq-compare.rs | 18 +- src/test/run-pass/shebang.rs | 3 - .../run-pass/simd-intrinsic-generic-cast.rs | 1 + .../simd-intrinsic-generic-elements.rs | 2 - src/test/run-pass/size-and-align.rs | 2 +- src/test/run-pass/static-impl.rs | 6 +- src/test/run-pass/struct-field-shorthand.rs | 37 + .../struct-path-associated-type.rs} | 32 +- src/test/run-pass/struct-path-self.rs | 56 + src/test/run-pass/super-fast-paren-parsing.rs | 2 - src/test/run-pass/swap-2.rs | 2 +- .../run-pass/syntax-extension-source-utils.rs | 11 +- src/test/run-pass/task-comm-16.rs | 2 +- src/test/run-pass/task-comm-3.rs | 1 - src/test/run-pass/task-stderr.rs | 2 +- ...e-verification-for-explicit-return-type.rs | 1 - src/test/run-pass/test-runner-hides-main.rs | 2 - .../run-pass/test-should-fail-good-message.rs | 2 - src/test/run-pass/trait-bounds-in-arc.rs | 6 +- src/test/run-pass/trait-generic.rs | 8 +- src/test/run-pass/trait-to-str.rs | 6 +- .../run-pass/traits-elaborate-type-region.rs | 58 + src/test/run-pass/type-macros-simple.rs | 2 +- .../run-pass/typeck-fn-to-unsafe-fn-ptr.rs | 21 + .../unboxed-closures-counter-not-moved.rs | 2 +- ...ures-move-some-upvars-in-by-ref-closure.rs | 4 +- src/test/run-pass/union/union-backcomp.rs | 6 + .../union/union-with-drop-fields-lint.rs | 2 - src/test/run-pass/uniq-self-in-mut-slot.rs | 2 +- src/test/run-pass/unique-autoderef-index.rs | 2 +- src/test/run-pass/unique-create.rs | 2 +- src/test/run-pass/unique-drop-complex.rs | 2 +- src/test/run-pass/unique-in-vec-copy.rs | 2 +- src/test/run-pass/unique-in-vec.rs | 2 +- src/test/run-pass/unsized2.rs | 8 +- src/test/run-pass/utf8_chars.rs | 2 +- src/test/run-pass/vec-concat.rs | 4 +- src/test/run-pass/vec-growth.rs | 2 +- src/test/run-pass/vec-late-init.rs | 2 +- .../run-pass/vec-macro-with-trailing-comma.rs | 4 +- src/test/run-pass/vec-matching.rs | 15 + src/test/run-pass/vec-push.rs | 2 +- src/test/run-pass/vec-to_str.rs | 4 +- src/test/run-pass/vec.rs | 2 +- src/test/run-pass/while-with-break.rs | 2 +- src/test/rustdoc/line-breaks.rs | 21 + src/test/rustdoc/playground-empty.rs | 21 + src/test/rustdoc/playground-none.rs | 19 + src/test/rustdoc/playground.rs | 39 + .../rustc-macro-crate.rs} | 15 +- src/test/ui/check_match/issue-35609.rs | 53 + src/test/ui/check_match/issue-35609.stderr | 50 + .../ui/compare-method/proj-outlives-region.rs | 27 + .../proj-outlives-region.stderr | 19 + .../proj-outlives-region.stdout | 0 .../compare-method/region-extra-2.rs} | 2 +- .../ui/compare-method/region-extra-2.stderr | 11 + src/test/ui/compare-method/region-extra.rs | 27 + .../ui/compare-method/region-extra.stderr | 11 + .../ui/compare-method/region-extra.stdout | 0 .../ui/compare-method/region-unrelated.rs | 28 + .../ui/compare-method/region-unrelated.stderr | 19 + .../ui/compare-method/region-unrelated.stdout | 0 .../compare-method/reordered-type-param.rs} | 2 + .../reordered-type-param.stderr | 14 + .../trait-bound-on-type-parameter.rs} | 9 +- .../trait-bound-on-type-parameter.stderr | 11 + .../compare-method/traits-misc-mismatch-1.rs} | 14 +- .../traits-misc-mismatch-1.stderr | 65 + .../compare-method/traits-misc-mismatch-2.rs} | 2 +- .../traits-misc-mismatch-2.stderr | 11 + src/test/ui/did_you_mean/issue-36798.rs | 18 + src/test/ui/did_you_mean/issue-36798.stderr | 8 + .../did_you_mean/issue-36798_unknown_field.rs | 18 + .../issue-36798_unknown_field.stderr | 8 + .../auxiliary/dropck_eyepatch_extern_crate.rs | 48 + .../ui/dropck/dropck-eyepatch-extern-crate.rs | 55 + .../dropck-eyepatch-extern-crate.stderr | 46 + .../dropck-eyepatch-implies-unsafe-impl.rs | 46 + ...dropck-eyepatch-implies-unsafe-impl.stderr | 14 + src/test/ui/dropck/dropck-eyepatch-reorder.rs | 73 + .../ui/dropck/dropck-eyepatch-reorder.stderr | 46 + src/test/ui/dropck/dropck-eyepatch.rs | 96 ++ src/test/ui/dropck/dropck-eyepatch.stderr | 46 + .../macro-backtrace-invalid-internals.stderr | 12 +- src/test/ui/span/E0057.rs | 16 + src/test/ui/span/E0057.stderr | 18 + .../span}/borrowck-let-suggestion-suffixes.rs | 8 +- .../borrowck-let-suggestion-suffixes.stderr | 52 + .../span}/borrowck-ref-into-rvalue.rs | 0 .../ui/span/borrowck-ref-into-rvalue.stderr | 16 + .../span}/destructor-restrictions.rs | 0 .../ui/span/destructor-restrictions.stderr | 12 + .../span}/dropck-object-cycle.rs | 6 +- src/test/ui/span/dropck-object-cycle.stderr | 13 + .../span}/dropck_arr_cycle_checked.rs | 18 +- .../ui/span/dropck_arr_cycle_checked.stderr | 67 + .../span}/dropck_direct_cycle_with_drop.rs | 6 +- .../span/dropck_direct_cycle_with_drop.stderr | 23 + .../span}/dropck_misc_variants.rs | 4 +- src/test/ui/span/dropck_misc_variants.stderr | 23 + .../span}/dropck_vec_cycle_checked.rs | 18 +- .../ui/span/dropck_vec_cycle_checked.stderr | 67 + src/test/ui/span/issue-11925.stderr | 4 +- ...e-23338-locals-die-before-temps-of-body.rs | 3 +- ...338-locals-die-before-temps-of-body.stderr | 22 + src/test/ui/span/issue-24690.rs | 22 + src/test/ui/span/issue-24690.stderr | 32 + ...24805-dropck-child-has-items-via-parent.rs | 3 +- ...5-dropck-child-has-items-via-parent.stderr | 13 + .../issue-24805-dropck-trait-has-items.rs | 9 +- .../issue-24805-dropck-trait-has-items.stderr | 32 + .../span}/issue-24895-copy-clone-dropck.rs | 4 +- .../span/issue-24895-copy-clone-dropck.stderr | 12 + .../{compile-fail => ui/span}/issue-25199.rs | 6 +- src/test/ui/span/issue-25199.stderr | 23 + .../{compile-fail => ui/span}/issue-26656.rs | 2 +- src/test/ui/span/issue-26656.stderr | 12 + .../{compile-fail => ui/span}/issue-29106.rs | 8 +- src/test/ui/span/issue-29106.stderr | 22 + src/test/ui/span/issue-36537.rs | 18 + src/test/ui/span/issue-36537.stderr | 12 + .../span}/issue28498-reject-ex1.rs | 4 +- src/test/ui/span/issue28498-reject-ex1.stderr | 23 + .../span}/issue28498-reject-lifetime-param.rs | 4 +- .../issue28498-reject-lifetime-param.stderr | 24 + .../span}/issue28498-reject-passed-to-fn.rs | 4 +- .../issue28498-reject-passed-to-fn.stderr | 24 + .../span}/issue28498-reject-trait-bound.rs | 4 +- .../span/issue28498-reject-trait-bound.stderr | 24 + .../impl-trait => ui/span}/loan-extend.rs | 9 +- src/test/ui/span/loan-extend.stderr | 13 + .../span}/mut-ptr-cant-outlive-ref.rs | 0 .../ui/span/mut-ptr-cant-outlive-ref.stderr | 12 + src/test/{compile-fail => ui/span}/range-2.rs | 0 src/test/ui/span/range-2.stderr | 24 + .../regionck-unboxed-closure-lifetimes.rs | 0 .../regionck-unboxed-closure-lifetimes.stderr | 13 + .../regions-close-over-type-parameter-2.rs | 0 ...regions-close-over-type-parameter-2.stderr | 13 + .../span}/regions-escape-loop-via-variable.rs | 0 .../regions-escape-loop-via-variable.stderr | 12 + .../span}/regions-escape-loop-via-vec.rs | 2 +- .../span/regions-escape-loop-via-vec.stderr | 41 + .../regions-infer-borrow-scope-within-loop.rs | 0 ...ions-infer-borrow-scope-within-loop.stderr | 14 + .../send-is-not-static-ensures-scoping.rs | 0 .../send-is-not-static-ensures-scoping.stderr | 28 + .../span}/send-is-not-static-std-sync-2.rs | 0 .../span/send-is-not-static-std-sync-2.stderr | 36 + .../span}/send-is-not-static-std-sync.rs | 0 .../span/send-is-not-static-std-sync.stderr | 56 + src/test/ui/span/type-binding.stderr | 2 +- .../vec-must-not-hide-type-from-dropck.rs | 6 +- .../vec-must-not-hide-type-from-dropck.stderr | 23 + .../span}/vec_refs_data_with_early_death.rs | 6 +- .../vec_refs_data_with_early_death.stderr | 24 + .../span}/wf-method-late-bound-regions.rs | 0 .../span/wf-method-late-bound-regions.stderr | 13 + src/test/ui/update-references.sh | 4 +- src/tools/cargotest/Cargo.lock | 4 - src/tools/cargotest/main.rs | 16 +- src/tools/compiletest/Cargo.lock | 92 -- src/tools/compiletest/Cargo.toml | 4 +- src/tools/compiletest/src/common.rs | 11 +- src/tools/compiletest/src/header.rs | 23 +- src/tools/compiletest/src/main.rs | 195 ++- src/tools/compiletest/src/runtest.rs | 166 ++- src/tools/compiletest/src/util.rs | 3 +- src/tools/error_index_generator/Cargo.lock | 4 - src/tools/error_index_generator/main.rs | 5 +- src/tools/linkchecker/Cargo.lock | 50 - src/tools/rustbook/Cargo.lock | 4 - src/tools/rustbook/book.rs | 10 +- src/tools/rustbook/build.rs | 7 +- src/tools/tidy/Cargo.lock | 4 - src/tools/tidy/src/bins.rs | 25 +- src/tools/tidy/src/cargo.rs | 8 +- src/tools/tidy/src/features.rs | 113 +- src/tools/tidy/src/main.rs | 2 + src/tools/tidy/src/pal.rs | 226 ++++ version | 2 +- 1523 files changed, 37407 insertions(+), 22584 deletions(-) create mode 100644 mk/cfg/aarch64-unknown-fuchsia.mk create mode 100644 mk/cfg/wasm32-unknown-emscripten.mk create mode 100644 mk/cfg/x86_64-unknown-fuchsia.mk delete mode 100644 src/bootstrap/Cargo.lock create mode 100644 src/bootstrap/install.rs create mode 100644 src/bootstrap/metadata.rs create mode 100644 src/libcollectionstest/cow_str.rs create mode 100644 src/libcore/internal_macros.rs create mode 100644 src/liblibc/ci/docker/mips64-unknown-linux-gnuabi64/Dockerfile delete mode 100644 src/libpanic_unwind/Cargo.lock create mode 100644 src/libpanic_unwind/emcc.rs create mode 100644 src/libproc_macro_plugin/Cargo.toml create mode 100644 src/libproc_macro_plugin/lib.rs rename src/{libproc_macro => libproc_macro_plugin}/qquote.rs (98%) rename src/{librustc_macro => libproc_macro_tokens}/Cargo.toml (62%) rename src/{libproc_macro => libproc_macro_tokens}/build.rs (100%) create mode 100644 src/libproc_macro_tokens/lib.rs rename src/{libproc_macro => libproc_macro_tokens}/parse.rs (100%) rename src/{libproc_macro => libproc_macro_tokens}/prelude.rs (100%) delete mode 100644 src/librustc/mir/mir_map.rs rename src/librustc/mir/{repr.rs => mod.rs} (86%) delete mode 100644 src/librustc_back/sha2.rs create mode 100644 src/librustc_back/target/aarch64_unknown_fuchsia.rs create mode 100644 src/librustc_back/target/arm_base.rs create mode 100644 src/librustc_back/target/fuchsia_base.rs create mode 100644 src/librustc_back/target/thumb_base.rs create mode 100644 src/librustc_back/target/thumbv6m_none_eabi.rs create mode 100644 src/librustc_back/target/thumbv7em_none_eabi.rs create mode 100644 src/librustc_back/target/thumbv7em_none_eabihf.rs create mode 100644 src/librustc_back/target/thumbv7m_none_eabi.rs create mode 100644 src/librustc_back/target/wasm32_unknown_emscripten.rs create mode 100644 src/librustc_back/target/x86_64_unknown_fuchsia.rs create mode 100644 src/librustc_const_eval/_match.rs create mode 100644 src/librustc_const_eval/pattern.rs create mode 100644 src/librustc_data_structures/accumulate_vec.rs create mode 100644 src/librustc_data_structures/array_vec.rs rename src/{librustc_borrowck => librustc_data_structures}/bitslice.rs (98%) create mode 100644 src/librustc_data_structures/blake2b.rs create mode 100644 src/librustc_data_structures/fmt_wrap.rs rename src/{librustc_borrowck => librustc_data_structures}/indexed_set.rs (98%) create mode 100644 src/librustc_errors/diagnostic.rs create mode 100644 src/librustc_errors/diagnostic_builder.rs create mode 100644 src/librustc_incremental/calculate_svh/hasher.rs create mode 100644 src/librustc_incremental/ich/fingerprint.rs create mode 100644 src/librustc_incremental/ich/mod.rs delete mode 100644 src/librustc_macro/lib.rs rename src/librustc_metadata/{csearch.rs => cstore_impl.rs} (94%) rename src/librustc_metadata/{loader.rs => locator.rs} (79%) delete mode 100644 src/librustc_metadata/macro_import.rs delete mode 100644 src/librustc_mir/hair/cx/pattern.rs rename src/librustc_mir/transform/{simplify_cfg.rs => simplify.rs} (62%) create mode 100644 src/librustc_passes/hir_stats.rs delete mode 100644 src/librustdoc/html/static/playpen.js rename src/libstd/{num => }/f32.rs (100%) rename src/libstd/{num => }/f64.rs (100%) rename src/libstd/{num/mod.rs => num.rs} (100%) create mode 100644 src/libstd/os/fuchsia/fs.rs create mode 100644 src/libstd/os/fuchsia/mod.rs create mode 100644 src/libstd/os/fuchsia/raw.rs delete mode 100644 src/libstd/sys/common/args.rs create mode 100644 src/libstd/sys/mod.rs create mode 100644 src/libstd/sys/unix/args.rs create mode 100644 src/libstd/sys/unix/env.rs create mode 100644 src/libstd/sys/unix/fast_thread_local.rs create mode 100644 src/libstd/sys/unix/memchr.rs create mode 100644 src/libstd/sys/unix/path.rs create mode 100644 src/libstd/sys/windows/args.rs create mode 100644 src/libstd/sys/windows/env.rs create mode 100644 src/libstd/sys/windows/memchr.rs create mode 100644 src/libstd/sys/windows/path.rs rename src/libstd/{sys/common => sys_common}/at_exit_imp.rs (100%) rename src/libstd/{sys/common => sys_common}/backtrace.rs (100%) rename src/libstd/{sys/common => sys_common}/condvar.rs (100%) rename src/libstd/{sys/common => sys_common}/gnu/libbacktrace.rs (100%) rename src/libstd/{sys/common => sys_common}/gnu/mod.rs (100%) rename src/libstd/{sys/common => sys_common}/io.rs (97%) create mode 100644 src/libstd/sys_common/memchr.rs rename src/libstd/{sys/common => sys_common}/mod.rs (82%) rename src/libstd/{sys/common => sys_common}/mutex.rs (100%) rename src/libstd/{sys/common => sys_common}/net.rs (96%) rename src/libstd/{sys/common => sys_common}/poison.rs (100%) rename src/libstd/{sys/common => sys_common}/remutex.rs (99%) rename src/libstd/{sys/common => sys_common}/rwlock.rs (100%) rename src/libstd/{sys/common => sys_common}/thread.rs (100%) rename src/libstd/{sys/common => sys_common}/thread_info.rs (100%) rename src/libstd/{sys/common => sys_common}/thread_local.rs (100%) rename src/libstd/{sys/common => sys_common}/util.rs (58%) rename src/libstd/{sys/common => sys_common}/wtf8.rs (98%) rename src/libsyntax_ext/{rustc_macro_registrar.rs => proc_macro_registrar.rs} (77%) delete mode 100644 src/rustc/Cargo.lock delete mode 100644 src/rustc/std_shim/Cargo.lock delete mode 100644 src/rustc/test_shim/Cargo.lock create mode 100644 src/test/codegen/enum-bounds-check.rs rename src/test/compile-fail-fulldeps/{macro-crate-unknown-crate.rs => no-link-unknown-crate.rs} (95%) rename src/test/compile-fail-fulldeps/{rustc-macro => proc-macro}/at-the-root.rs (73%) create mode 100644 src/test/compile-fail-fulldeps/proc-macro/attribute.rs rename src/test/compile-fail-fulldeps/{rustc-macro => proc-macro}/auxiliary/derive-a.rs (77%) rename src/test/compile-fail-fulldeps/{rustc-macro => proc-macro}/auxiliary/derive-bad.rs (78%) rename src/test/compile-fail-fulldeps/{rustc-macro => proc-macro}/auxiliary/derive-panic.rs (77%) rename src/test/compile-fail-fulldeps/{rustc-macro => proc-macro}/auxiliary/derive-unstable-2.rs (78%) rename src/test/compile-fail-fulldeps/{rustc-macro => proc-macro}/auxiliary/derive-unstable.rs (78%) rename src/test/compile-fail-fulldeps/{rustc-macro => proc-macro}/cannot-link.rs (87%) rename src/test/compile-fail-fulldeps/{rustc-macro => proc-macro}/define-two.rs (74%) rename src/test/compile-fail-fulldeps/{rustc-macro => proc-macro}/derive-bad.rs (96%) rename src/test/compile-fail-fulldeps/{rustc-macro => proc-macro}/derive-still-gated.rs (96%) rename src/test/compile-fail-fulldeps/{rustc-macro => proc-macro}/expand-to-unstable-2.rs (96%) rename src/test/compile-fail-fulldeps/{rustc-macro => proc-macro}/expand-to-unstable.rs (96%) rename src/test/compile-fail-fulldeps/{rustc-macro => proc-macro}/export-macro.rs (79%) rename src/test/compile-fail-fulldeps/{rustc-macro => proc-macro}/exports.rs (95%) rename src/test/compile-fail-fulldeps/{rustc-macro => proc-macro}/feature-gate-1.rs (83%) rename src/test/compile-fail-fulldeps/{rustc-macro => proc-macro}/feature-gate-2.rs (87%) rename src/test/compile-fail-fulldeps/{rustc-macro => proc-macro}/feature-gate-3.rs (83%) rename src/test/compile-fail-fulldeps/{rustc-macro => proc-macro}/feature-gate-4.rs (100%) rename src/test/compile-fail-fulldeps/{rustc-macro => proc-macro}/feature-gate-5.rs (87%) create mode 100644 src/test/compile-fail-fulldeps/proc-macro/illegal-proc-macro-derive-use.rs rename src/test/compile-fail-fulldeps/{rustc-macro => proc-macro}/import.rs (96%) rename src/test/compile-fail-fulldeps/{rustc-macro => proc-macro}/load-panic.rs (96%) rename src/test/compile-fail-fulldeps/{rustc-macro => proc-macro}/shadow-builtin.rs (80%) rename src/test/compile-fail-fulldeps/{rustc-macro => proc-macro}/shadow.rs (81%) rename src/test/compile-fail-fulldeps/{rustc-macro => proc-macro}/signature.rs (78%) rename src/test/compile-fail-fulldeps/{rustc-macro => proc-macro}/two-crate-types-1.rs (83%) rename src/test/compile-fail-fulldeps/{rustc-macro => proc-macro}/two-crate-types-2.rs (78%) delete mode 100644 src/test/compile-fail-fulldeps/rustc-macro/attribute.rs rename src/test/compile-fail/{E0002.rs => E0004-2.rs} (94%) create mode 100644 src/test/compile-fail/E0198.rs create mode 100644 src/test/compile-fail/associated-path-shl.rs create mode 100644 src/test/compile-fail/attr-on-generic-formals-are-visited.rs create mode 100644 src/test/compile-fail/attr-on-generic-formals-wo-feature-gate.rs create mode 100644 src/test/compile-fail/attrs-with-no-formal-in-generics-1.rs create mode 100644 src/test/compile-fail/attrs-with-no-formal-in-generics-2.rs create mode 100644 src/test/compile-fail/attrs-with-no-formal-in-generics-3.rs create mode 100644 src/test/compile-fail/auxiliary/define_macro.rs create mode 100644 src/test/compile-fail/auxiliary/import_crate_var.rs create mode 100644 src/test/compile-fail/auxiliary/namespace-mix-new.rs create mode 100644 src/test/compile-fail/auxiliary/namespace-mix-old.rs create mode 100644 src/test/compile-fail/dep-graph-type-alias.rs delete mode 100644 src/test/compile-fail/empty-struct-unit-pat-1.rs delete mode 100644 src/test/compile-fail/empty-struct-unit-pat-2.rs create mode 100644 src/test/compile-fail/empty-struct-unit-pat.rs rename src/test/compile-fail/{pat-tuple-feature-gate.rs => feature-gate-field-init-shorthand.rs} (66%) create mode 100644 src/test/compile-fail/feature-gate-may-dangle.rs create mode 100644 src/test/compile-fail/feature-gate-no-debug-2.rs create mode 100644 src/test/compile-fail/import-crate-var.rs create mode 100644 src/test/compile-fail/issue-18937.rs create mode 100644 src/test/compile-fail/issue-21837.rs create mode 100644 src/test/compile-fail/issue-26158.rs create mode 100644 src/test/compile-fail/issue-36116.rs rename src/test/compile-fail/{E0422.rs => issue-36881.rs} (83%) create mode 100644 src/test/compile-fail/issue-37026.rs create mode 100644 src/test/compile-fail/issue-37534.rs rename src/test/{run-pass => compile-fail}/issue-pr29383.rs (74%) rename src/test/{parse-fail => compile-fail}/keyword-self-as-identifier.rs (81%) rename src/test/{parse-fail => compile-fail}/keyword-super-as-identifier.rs (81%) rename src/test/{parse-fail => compile-fail}/keyword-super.rs (81%) create mode 100644 src/test/compile-fail/macro-shadowing.rs create mode 100644 src/test/compile-fail/match-byte-array-patterns.rs create mode 100644 src/test/compile-fail/namespace-mix-new.rs create mode 100644 src/test/compile-fail/namespace-mix-old.rs create mode 100644 src/test/compile-fail/no-patterns-in-args-2.rs rename src/test/{compile-fail-fulldeps/rustc-macro/require-rustc-macro-crate-type.rs => compile-fail/out-of-order-shadowing.rs} (68%) create mode 100644 src/test/compile-fail/self-vs-path-ambiguity.rs create mode 100644 src/test/compile-fail/struct-fields-shorthand-unresolved.rs create mode 100644 src/test/compile-fail/struct-fields-shorthand.rs create mode 100644 src/test/compile-fail/struct-path-alias-bounds.rs create mode 100644 src/test/compile-fail/struct-path-associated-type.rs create mode 100644 src/test/compile-fail/struct-path-self-feature-gate.rs create mode 100644 src/test/compile-fail/struct-path-self-type-mismatch.rs create mode 100644 src/test/compile-fail/struct-path-self.rs create mode 100644 src/test/compile-fail/unsized-enum2.rs create mode 100644 src/test/compile-fail/windows-subsystem-gated.rs create mode 100644 src/test/compile-fail/windows-subsystem-invalid.rs create mode 100644 src/test/debuginfo/drop-locations.rs rename src/test/{run-pass/lint-non-uppercase-statics-lowercase-mut-statics.rs => incremental/change_crate_order/auxiliary/a.rs} (65%) create mode 100644 src/test/incremental/change_crate_order/auxiliary/b.rs create mode 100644 src/test/incremental/change_crate_order/main.rs create mode 100644 src/test/incremental/change_private_fn/struct_point.rs create mode 100644 src/test/incremental/change_private_fn_cc/auxiliary/point.rs create mode 100644 src/test/incremental/change_private_fn_cc/struct_point.rs create mode 100644 src/test/incremental/change_private_impl_method/struct_point.rs create mode 100644 src/test/incremental/change_private_impl_method_cc/auxiliary/point.rs create mode 100644 src/test/incremental/change_private_impl_method_cc/struct_point.rs create mode 100644 src/test/incremental/hashes/consts.rs create mode 100644 src/test/incremental/hashes/enum_defs.rs create mode 100644 src/test/incremental/hashes/function_interfaces.rs create mode 100644 src/test/incremental/hashes/panic_exprs.rs create mode 100644 src/test/incremental/hashes/panic_exprs_no_overflow_checks.rs create mode 100644 src/test/incremental/hashes/statics.rs create mode 100644 src/test/incremental/hashes/trait_defs.rs create mode 100644 src/test/parse-fail/issue-37113.rs create mode 100644 src/test/parse-fail/recover-enum.rs create mode 100644 src/test/parse-fail/recover-enum2.rs create mode 100644 src/test/parse-fail/recover-struct.rs create mode 100644 src/test/parse-fail/struct-field-numeric-shorthand.rs create mode 100644 src/test/run-make/rustc-macro-dep-files/Makefile create mode 100644 src/test/run-make/rustc-macro-dep-files/bar.rs create mode 100644 src/test/run-make/rustc-macro-dep-files/foo.rs create mode 100644 src/test/run-make/target-without-atomics/Makefile create mode 100644 src/test/run-make/windows-subsystem/Makefile create mode 100644 src/test/run-make/windows-subsystem/console.rs create mode 100644 src/test/run-make/windows-subsystem/windows.rs rename src/test/run-pass-fulldeps/{rustc-macro => proc-macro}/add-impl.rs (96%) rename src/test/{compile-fail-fulldeps/rustc-macro => run-pass-fulldeps/proc-macro}/append-impl.rs (88%) rename src/test/run-pass-fulldeps/{rustc-macro => proc-macro}/auxiliary/add-impl.rs (78%) rename src/test/{compile-fail-fulldeps/rustc-macro => run-pass-fulldeps/proc-macro}/auxiliary/append-impl.rs (80%) rename src/test/run-pass-fulldeps/{rustc-macro => proc-macro}/auxiliary/derive-a.rs (66%) rename src/test/run-pass-fulldeps/{rustc-macro => proc-macro}/auxiliary/derive-atob.rs (73%) rename src/test/run-pass-fulldeps/{rustc-macro => proc-macro}/auxiliary/derive-ctod.rs (79%) rename src/test/run-pass-fulldeps/{rustc-macro => proc-macro}/auxiliary/derive-same-struct.rs (80%) rename src/test/run-pass-fulldeps/{rustc-macro => proc-macro}/auxiliary/expand-with-a-macro.rs (82%) rename src/test/run-pass-fulldeps/{rustc-macro => proc-macro}/derive-same-struct.rs (96%) rename src/test/run-pass-fulldeps/{rustc-macro => proc-macro}/expand-with-a-macro.rs (96%) rename src/test/run-pass-fulldeps/{rustc-macro => proc-macro}/load-two.rs (93%) rename src/test/run-pass-fulldeps/{rustc-macro => proc-macro}/smoke.rs (96%) create mode 100644 src/test/run-pass/attr-on-generic-formals.rs create mode 100644 src/test/run-pass/auxiliary/dropck_eyepatch_extern_crate.rs create mode 100644 src/test/run-pass/auxiliary/issue-36954.rs delete mode 100644 src/test/run-pass/cstring-drop.rs create mode 100644 src/test/run-pass/discriminant_value-wrapper.rs create mode 100644 src/test/run-pass/dropck-eyepatch-extern-crate.rs create mode 100644 src/test/run-pass/dropck-eyepatch-reorder.rs create mode 100644 src/test/run-pass/dropck-eyepatch.rs create mode 100644 src/test/run-pass/issue-18060.rs create mode 100644 src/test/run-pass/issue-18088.rs create mode 100644 src/test/run-pass/issue-18937-1.rs create mode 100644 src/test/run-pass/issue-36768.rs create mode 100644 src/test/run-pass/issue-36786-resolve-call.rs create mode 100644 src/test/run-pass/issue-36816.rs create mode 100644 src/test/run-pass/issue-36954.rs create mode 100644 src/test/run-pass/issue-37175.rs create mode 100644 src/test/run-pass/issue-37686.rs create mode 100644 src/test/run-pass/issue-38002.rs create mode 100644 src/test/run-pass/issue-38033.rs create mode 100644 src/test/run-pass/iter-step-overflow-debug.rs create mode 100644 src/test/run-pass/iter-step-overflow-ndebug.rs create mode 100644 src/test/run-pass/iter-zip.rs create mode 100644 src/test/run-pass/match-byte-array-patterns.rs create mode 100644 src/test/run-pass/nonzero-enum.rs create mode 100644 src/test/run-pass/project-cache-issue-37154.rs create mode 100644 src/test/run-pass/struct-field-shorthand.rs rename src/test/{compile-fail/struct-pat-associated-path.rs => run-pass/struct-path-associated-type.rs} (59%) create mode 100644 src/test/run-pass/struct-path-self.rs create mode 100644 src/test/run-pass/traits-elaborate-type-region.rs create mode 100644 src/test/run-pass/typeck-fn-to-unsafe-fn-ptr.rs create mode 100644 src/test/rustdoc/line-breaks.rs create mode 100644 src/test/rustdoc/playground-empty.rs create mode 100644 src/test/rustdoc/playground-none.rs create mode 100644 src/test/rustdoc/playground.rs rename src/test/{compile-fail-fulldeps/rustc-macro/auxiliary/derive-a-2.rs => rustdoc/rustc-macro-crate.rs} (68%) create mode 100644 src/test/ui/check_match/issue-35609.rs create mode 100644 src/test/ui/check_match/issue-35609.stderr create mode 100644 src/test/ui/compare-method/proj-outlives-region.rs create mode 100644 src/test/ui/compare-method/proj-outlives-region.stderr create mode 100644 src/test/ui/compare-method/proj-outlives-region.stdout rename src/test/{compile-fail/region-bound-extra-bound-in-impl.rs => ui/compare-method/region-extra-2.rs} (94%) create mode 100644 src/test/ui/compare-method/region-extra-2.stderr create mode 100644 src/test/ui/compare-method/region-extra.rs create mode 100644 src/test/ui/compare-method/region-extra.stderr create mode 100644 src/test/ui/compare-method/region-extra.stdout create mode 100644 src/test/ui/compare-method/region-unrelated.rs create mode 100644 src/test/ui/compare-method/region-unrelated.stderr create mode 100644 src/test/ui/compare-method/region-unrelated.stdout rename src/test/{compile-fail/issue-2611-5.rs => ui/compare-method/reordered-type-param.rs} (98%) create mode 100644 src/test/ui/compare-method/reordered-type-param.stderr rename src/test/{compile-fail/issue-2611-4.rs => ui/compare-method/trait-bound-on-type-parameter.rs} (71%) create mode 100644 src/test/ui/compare-method/trait-bound-on-type-parameter.stderr rename src/test/{compile-fail/trait-bounds-impl-comparison-1.rs => ui/compare-method/traits-misc-mismatch-1.rs} (82%) create mode 100644 src/test/ui/compare-method/traits-misc-mismatch-1.stderr rename src/test/{compile-fail/trait-bounds-impl-comparison-2.rs => ui/compare-method/traits-misc-mismatch-2.rs} (92%) create mode 100644 src/test/ui/compare-method/traits-misc-mismatch-2.stderr create mode 100644 src/test/ui/did_you_mean/issue-36798.rs create mode 100644 src/test/ui/did_you_mean/issue-36798.stderr create mode 100644 src/test/ui/did_you_mean/issue-36798_unknown_field.rs create mode 100644 src/test/ui/did_you_mean/issue-36798_unknown_field.stderr create mode 100644 src/test/ui/dropck/auxiliary/dropck_eyepatch_extern_crate.rs create mode 100644 src/test/ui/dropck/dropck-eyepatch-extern-crate.rs create mode 100644 src/test/ui/dropck/dropck-eyepatch-extern-crate.stderr create mode 100644 src/test/ui/dropck/dropck-eyepatch-implies-unsafe-impl.rs create mode 100644 src/test/ui/dropck/dropck-eyepatch-implies-unsafe-impl.stderr create mode 100644 src/test/ui/dropck/dropck-eyepatch-reorder.rs create mode 100644 src/test/ui/dropck/dropck-eyepatch-reorder.stderr create mode 100644 src/test/ui/dropck/dropck-eyepatch.rs create mode 100644 src/test/ui/dropck/dropck-eyepatch.stderr create mode 100644 src/test/ui/span/E0057.rs create mode 100644 src/test/ui/span/E0057.stderr rename src/test/{compile-fail/borrowck => ui/span}/borrowck-let-suggestion-suffixes.rs (89%) create mode 100644 src/test/ui/span/borrowck-let-suggestion-suffixes.stderr rename src/test/{compile-fail/borrowck => ui/span}/borrowck-ref-into-rvalue.rs (100%) create mode 100644 src/test/ui/span/borrowck-ref-into-rvalue.stderr rename src/test/{compile-fail => ui/span}/destructor-restrictions.rs (100%) create mode 100644 src/test/ui/span/destructor-restrictions.stderr rename src/test/{compile-fail => ui/span}/dropck-object-cycle.rs (89%) create mode 100644 src/test/ui/span/dropck-object-cycle.stderr rename src/test/{compile-fail => ui/span}/dropck_arr_cycle_checked.rs (84%) create mode 100644 src/test/ui/span/dropck_arr_cycle_checked.stderr rename src/test/{compile-fail => ui/span}/dropck_direct_cycle_with_drop.rs (92%) create mode 100644 src/test/ui/span/dropck_direct_cycle_with_drop.stderr rename src/test/{compile-fail => ui/span}/dropck_misc_variants.rs (92%) create mode 100644 src/test/ui/span/dropck_misc_variants.stderr rename src/test/{compile-fail => ui/span}/dropck_vec_cycle_checked.rs (85%) create mode 100644 src/test/ui/span/dropck_vec_cycle_checked.stderr rename src/test/{compile-fail => ui/span}/issue-23338-locals-die-before-temps-of-body.rs (94%) create mode 100644 src/test/ui/span/issue-23338-locals-die-before-temps-of-body.stderr create mode 100644 src/test/ui/span/issue-24690.rs create mode 100644 src/test/ui/span/issue-24690.stderr rename src/test/{compile-fail => ui/span}/issue-24805-dropck-child-has-items-via-parent.rs (95%) create mode 100644 src/test/ui/span/issue-24805-dropck-child-has-items-via-parent.stderr rename src/test/{compile-fail => ui/span}/issue-24805-dropck-trait-has-items.rs (88%) create mode 100644 src/test/ui/span/issue-24805-dropck-trait-has-items.stderr rename src/test/{compile-fail => ui/span}/issue-24895-copy-clone-dropck.rs (93%) create mode 100644 src/test/ui/span/issue-24895-copy-clone-dropck.stderr rename src/test/{compile-fail => ui/span}/issue-25199.rs (93%) create mode 100644 src/test/ui/span/issue-25199.stderr rename src/test/{compile-fail => ui/span}/issue-26656.rs (96%) create mode 100644 src/test/ui/span/issue-26656.stderr rename src/test/{compile-fail => ui/span}/issue-29106.rs (83%) create mode 100644 src/test/ui/span/issue-29106.stderr create mode 100644 src/test/ui/span/issue-36537.rs create mode 100644 src/test/ui/span/issue-36537.stderr rename src/test/{compile-fail => ui/span}/issue28498-reject-ex1.rs (93%) create mode 100644 src/test/ui/span/issue28498-reject-ex1.stderr rename src/test/{compile-fail => ui/span}/issue28498-reject-lifetime-param.rs (92%) create mode 100644 src/test/ui/span/issue28498-reject-lifetime-param.stderr rename src/test/{compile-fail => ui/span}/issue28498-reject-passed-to-fn.rs (93%) create mode 100644 src/test/ui/span/issue28498-reject-passed-to-fn.stderr rename src/test/{compile-fail => ui/span}/issue28498-reject-trait-bound.rs (92%) create mode 100644 src/test/ui/span/issue28498-reject-trait-bound.stderr rename src/test/{compile-fail/impl-trait => ui/span}/loan-extend.rs (76%) create mode 100644 src/test/ui/span/loan-extend.stderr rename src/test/{compile-fail => ui/span}/mut-ptr-cant-outlive-ref.rs (100%) create mode 100644 src/test/ui/span/mut-ptr-cant-outlive-ref.stderr rename src/test/{compile-fail => ui/span}/range-2.rs (100%) create mode 100644 src/test/ui/span/range-2.stderr rename src/test/{compile-fail => ui/span}/regionck-unboxed-closure-lifetimes.rs (100%) create mode 100644 src/test/ui/span/regionck-unboxed-closure-lifetimes.stderr rename src/test/{compile-fail => ui/span}/regions-close-over-type-parameter-2.rs (100%) create mode 100644 src/test/ui/span/regions-close-over-type-parameter-2.stderr rename src/test/{compile-fail => ui/span}/regions-escape-loop-via-variable.rs (100%) create mode 100644 src/test/ui/span/regions-escape-loop-via-variable.stderr rename src/test/{compile-fail => ui/span}/regions-escape-loop-via-vec.rs (97%) create mode 100644 src/test/ui/span/regions-escape-loop-via-vec.stderr rename src/test/{compile-fail => ui/span}/regions-infer-borrow-scope-within-loop.rs (100%) create mode 100644 src/test/ui/span/regions-infer-borrow-scope-within-loop.stderr rename src/test/{compile-fail => ui/span}/send-is-not-static-ensures-scoping.rs (100%) create mode 100644 src/test/ui/span/send-is-not-static-ensures-scoping.stderr rename src/test/{compile-fail => ui/span}/send-is-not-static-std-sync-2.rs (100%) create mode 100644 src/test/ui/span/send-is-not-static-std-sync-2.stderr rename src/test/{compile-fail => ui/span}/send-is-not-static-std-sync.rs (100%) create mode 100644 src/test/ui/span/send-is-not-static-std-sync.stderr rename src/test/{compile-fail => ui/span}/vec-must-not-hide-type-from-dropck.rs (96%) create mode 100644 src/test/ui/span/vec-must-not-hide-type-from-dropck.stderr rename src/test/{compile-fail => ui/span}/vec_refs_data_with_early_death.rs (90%) create mode 100644 src/test/ui/span/vec_refs_data_with_early_death.stderr rename src/test/{compile-fail => ui/span}/wf-method-late-bound-regions.rs (100%) create mode 100644 src/test/ui/span/wf-method-late-bound-regions.stderr delete mode 100644 src/tools/cargotest/Cargo.lock delete mode 100644 src/tools/compiletest/Cargo.lock delete mode 100644 src/tools/error_index_generator/Cargo.lock delete mode 100644 src/tools/linkchecker/Cargo.lock delete mode 100644 src/tools/rustbook/Cargo.lock delete mode 100644 src/tools/tidy/Cargo.lock create mode 100644 src/tools/tidy/src/pal.rs diff --git a/README.md b/README.md index f2385f3151..7360651095 100644 --- a/README.md +++ b/README.md @@ -89,6 +89,7 @@ build. $ pacman -S git \ make \ diffutils \ + tar \ mingw-w64-x86_64-python2 \ mingw-w64-x86_64-cmake \ mingw-w64-x86_64-gcc @@ -126,7 +127,7 @@ ones from MSYS if you have it installed). You'll also need Visual Studio 2013 or newer with the C++ tools. Then all you need to do is to kick off rustbuild. ``` -python .\src\bootstrap\bootstrap.py +python x.py build ``` Currently rustbuild only works with some known versions of Visual Studio. If you @@ -136,7 +137,7 @@ by manually calling the appropriate vcvars file before running the bootstrap. ``` CALL "C:\Program Files (x86)\Microsoft Visual Studio 14.0\VC\bin\amd64\vcvars64.bat" -python .\src\bootstrap\bootstrap.py +python x.py build ``` ## Building Documentation diff --git a/RELEASES.md b/RELEASES.md index 4e815b9b8e..222ad3aa11 100644 --- a/RELEASES.md +++ b/RELEASES.md @@ -1,260 +1,3 @@ -Version 1.13.0 (2016-11-10) -=========================== - -Language --------- - -* [Stabilize the `?` operator][36995]. `?` is a simple way to propagate - errors, like the `try!` macro, described in [RFC 0243]. -* [Stabilize macros in type position][36014]. Described in [RFC 873]. -* [Stabilize attributes on statements][36995]. Described in [RFC 0016]. -* [Fix `#[derive]` for empty tuple structs/variants][35728] -* [Fix lifetime rules for 'if' conditions][36029] -* [Avoid loading and parsing unconfigured non-inline modules][36482] - -Compiler --------- - -* [Add the `-C link-arg` argument][36574] -* [Remove the old AST-based backend from rustc_trans][35764] -* [Don't enable NEON by default on armv7 Linux][35814] -* [Fix debug line number info for macro expansions][35238] -* [Do not emit "class method" debuginfo for types that are not - DICompositeType][36008] -* [Warn about multiple conflicting #[repr] hints][34623] -* [When sizing DST, don't double-count nested struct prefixes][36351] -* [Default RUST_MIN_STACK to 16MiB for now][36505] -* [Improve rlib metadata format][36551]. Reduces rlib size significantly. -* [Reject macros with empty repetitions to avoid infinite loop][36721] -* [Expand macros without recursing to avoid stack overflows][36214] - -Diagnostics ------------ - -* [Replace macro backtraces with labeled local uses][35702] -* [Improve error message for missplaced doc comments][33922] -* [Buffer unix and lock windows to prevent message interleaving][35975] -* [Update lifetime errors to specifically note temporaries][36171] -* [Special case a few colors for Windows][36178] -* [Suggest `use self` when such an import resolves][36289] -* [Be more specific when type parameter shadows primitive type][36338] -* Many minor improvements - -Compile-time Optimizations --------------------------- - -* [Compute and cache HIR hashes at beginning][35854] -* [Don't hash types in loan paths][36004] -* [Cache projections in trans][35761] -* [Optimize the parser's last token handling][36527] -* [Only instantiate #[inline] functions in codegen units referencing - them][36524]. This leads to big improvements in cases where crates export - define many inline functions without using them directly. -* [Lazily allocate TypedArena's first chunk][36592] -* [Don't allocate during default HashSet creation][36734] - -Stabilized APIs ---------------- - -* [`checked_abs`] -* [`wrapping_abs`] -* [`overflowing_abs`] -* [`RefCell::try_borrow`] -* [`RefCell::try_borrow_mut`] - -Libraries ---------- - -* [Add `assert_ne!` and `debug_assert_ne!`][35074] -* [Make `vec_deque::Drain`, `hash_map::Drain`, and `hash_set::Drain` - covariant][35354] -* [Implement `AsRef<[T]>` for `std::slice::Iter`][35559] -* [Implement `Debug` for `std::vec::IntoIter`][35707] -* [`CString`: avoid excessive growth just to 0-terminate][35871] -* [Implement `CoerceUnsized` for `{Cell, RefCell, UnsafeCell}`][35627] -* [Use arc4rand on FreeBSD][35884] -* [memrchr: Correct aligned offset computation][35969] -* [Improve Demangling of Rust Symbols][36059] -* [Use monotonic time in condition variables][35048] -* [Implement `Debug` for `std::path::{Components,Iter}`][36101] -* [Implement conversion traits for `char`][35755] -* [Fix illegal instruction caused by overflow in channel cloning][36104] -* [Zero first byte of CString on drop][36264] -* [Inherit overflow checks for sum and product][36372] -* [Add missing Eq implementations][36423] -* [Implement `Debug` for `DirEntry`][36631] -* [When `getaddrinfo` returns `EAI_SYSTEM` retrieve actual error from - `errno`][36754] -* [`SipHasher`] is deprecated. Use [`DefaultHasher`]. -* [Implement more traits for `std::io::ErrorKind`][35911] -* [Optimize BinaryHeap bounds checking][36072] -* [Work around pointer aliasing issue in `Vec::extend_from_slice`, - `extend_with_element`][36355] -* [Fix overflow checking in unsigned pow()][34942] - -Cargo ------ - -* This release includes security fixes to both curl and OpenSSL. -* [Fix transitive doctests when panic=abort][cargo/3021] -* [Add --all-features flag to cargo][cargo/3038] -* [Reject path-based dependencies in `cargo package`][cargo/3060] -* [Don't parse the home directory more than once][cargo/3078] -* [Don't try to generate Cargo.lock on empty workspaces][cargo/3092] -* [Update OpenSSL to 1.0.2j][cargo/3121] -* [Add license and license_file to cargo metadata output][cargo/3110] -* [Make crates-io registry URL optional in config; ignore all changes to - source.crates-io][cargo/3089] -* [Don't download dependencies from other platforms][cargo/3123] -* [Build transitive dev-dependencies when needed][cargo/3125] -* [Add support for per-target rustflags in .cargo/config][cargo/3157] -* [Avoid updating registry when adding existing deps][cargo/3144] -* [Warn about path overrides that won't work][cargo/3136] -* [Use workspaces during `cargo install`][cargo/3146] -* [Leak mspdbsrv.exe processes on Windows][cargo/3162] -* [Add --message-format flag][cargo/3000] -* [Pass target environment for rustdoc][cargo/3205] -* [Use `CommandExt::exec` for `cargo run` on Unix][cargo/2818] -* [Update curl and curl-sys][cargo/3241] -* [Call rustdoc test with the correct cfg flags of a package][cargo/3242] - -Tooling -------- - -* [rustdoc: Add the `--sysroot` argument][36586] -* [rustdoc: Fix a couple of issues with the search results][35655] -* [rustdoc: remove the `!` from macro URLs and titles][35234] -* [gdb: Fix pretty-printing special-cased Rust types][35585] -* [rustdoc: Filter more incorrect methods inherited through Deref][36266] - -Misc ----- - -* [Remove unmaintained style guide][35124] -* [Add s390x support][36369] -* [Initial work at Haiku OS support][36727] -* [Add mips-uclibc targets][35734] -* [Crate-ify compiler-rt into compiler-builtins][35021] -* [Add rustc version info (git hash + date) to dist tarball][36213] -* Many documentation improvements - -Compatibility Notes -------------------- - -* [`SipHasher`] is deprecated. Use [`DefaultHasher`]. -* [Deny (by default) transmuting from fn item types to pointer-sized - types][34923]. Continuing the long transition to zero-sized fn items, - per [RFC 401]. -* [Fix `#[derive]` for empty tuple structs/variants][35728]. - Part of [RFC 1506]. -* [Issue deprecation warnings for safe accesses to extern statics][36173] -* [Fix lifetime rules for 'if' conditions][36029]. -* [Inherit overflow checks for sum and product][36372]. -* [Forbid user-defined macros named "macro_rules"][36730]. - -[33922]: https://github.com/rust-lang/rust/pull/33922 -[34623]: https://github.com/rust-lang/rust/pull/34623 -[34923]: https://github.com/rust-lang/rust/pull/34923 -[34942]: https://github.com/rust-lang/rust/pull/34942 -[34982]: https://github.com/rust-lang/rust/pull/34982 -[35021]: https://github.com/rust-lang/rust/pull/35021 -[35048]: https://github.com/rust-lang/rust/pull/35048 -[35074]: https://github.com/rust-lang/rust/pull/35074 -[35124]: https://github.com/rust-lang/rust/pull/35124 -[35234]: https://github.com/rust-lang/rust/pull/35234 -[35238]: https://github.com/rust-lang/rust/pull/35238 -[35354]: https://github.com/rust-lang/rust/pull/35354 -[35559]: https://github.com/rust-lang/rust/pull/35559 -[35585]: https://github.com/rust-lang/rust/pull/35585 -[35627]: https://github.com/rust-lang/rust/pull/35627 -[35655]: https://github.com/rust-lang/rust/pull/35655 -[35702]: https://github.com/rust-lang/rust/pull/35702 -[35707]: https://github.com/rust-lang/rust/pull/35707 -[35728]: https://github.com/rust-lang/rust/pull/35728 -[35734]: https://github.com/rust-lang/rust/pull/35734 -[35755]: https://github.com/rust-lang/rust/pull/35755 -[35761]: https://github.com/rust-lang/rust/pull/35761 -[35764]: https://github.com/rust-lang/rust/pull/35764 -[35814]: https://github.com/rust-lang/rust/pull/35814 -[35854]: https://github.com/rust-lang/rust/pull/35854 -[35871]: https://github.com/rust-lang/rust/pull/35871 -[35884]: https://github.com/rust-lang/rust/pull/35884 -[35911]: https://github.com/rust-lang/rust/pull/35911 -[35969]: https://github.com/rust-lang/rust/pull/35969 -[35975]: https://github.com/rust-lang/rust/pull/35975 -[36004]: https://github.com/rust-lang/rust/pull/36004 -[36008]: https://github.com/rust-lang/rust/pull/36008 -[36014]: https://github.com/rust-lang/rust/pull/36014 -[36029]: https://github.com/rust-lang/rust/pull/36029 -[36059]: https://github.com/rust-lang/rust/pull/36059 -[36072]: https://github.com/rust-lang/rust/pull/36072 -[36101]: https://github.com/rust-lang/rust/pull/36101 -[36104]: https://github.com/rust-lang/rust/pull/36104 -[36171]: https://github.com/rust-lang/rust/pull/36171 -[36173]: https://github.com/rust-lang/rust/pull/36173 -[36178]: https://github.com/rust-lang/rust/pull/36178 -[36213]: https://github.com/rust-lang/rust/pull/36213 -[36214]: https://github.com/rust-lang/rust/pull/36214 -[36264]: https://github.com/rust-lang/rust/pull/36264 -[36266]: https://github.com/rust-lang/rust/pull/36266 -[36289]: https://github.com/rust-lang/rust/pull/36289 -[36338]: https://github.com/rust-lang/rust/pull/36338 -[36351]: https://github.com/rust-lang/rust/pull/36351 -[36355]: https://github.com/rust-lang/rust/pull/36355 -[36369]: https://github.com/rust-lang/rust/pull/36369 -[36372]: https://github.com/rust-lang/rust/pull/36372 -[36423]: https://github.com/rust-lang/rust/pull/36423 -[36482]: https://github.com/rust-lang/rust/pull/36482 -[36505]: https://github.com/rust-lang/rust/pull/36505 -[36524]: https://github.com/rust-lang/rust/pull/36524 -[36527]: https://github.com/rust-lang/rust/pull/36527 -[36551]: https://github.com/rust-lang/rust/pull/36551 -[36574]: https://github.com/rust-lang/rust/pull/36574 -[36586]: https://github.com/rust-lang/rust/pull/36586 -[36592]: https://github.com/rust-lang/rust/pull/36592 -[36631]: https://github.com/rust-lang/rust/pull/36631 -[36639]: https://github.com/rust-lang/rust/pull/36639 -[36721]: https://github.com/rust-lang/rust/pull/36721 -[36727]: https://github.com/rust-lang/rust/pull/36727 -[36730]: https://github.com/rust-lang/rust/pull/36730 -[36734]: https://github.com/rust-lang/rust/pull/36734 -[36754]: https://github.com/rust-lang/rust/pull/36754 -[36995]: https://github.com/rust-lang/rust/pull/36995 -[RFC 0016]: https://github.com/rust-lang/rfcs/blob/master/text/0016-more-attributes.md -[RFC 0243]: https://github.com/rust-lang/rfcs/blob/master/text/0243-trait-based-exception-handling.md -[RFC 1506]: https://github.com/rust-lang/rfcs/blob/master/text/1506-adt-kinds.md -[RFC 401]: https://github.com/rust-lang/rfcs/blob/master/text/0401-coercions.md -[RFC 873]: https://github.com/rust-lang/rfcs/blob/master/text/0873-type-macros.md -[cargo/2818]: https://github.com/rust-lang/cargo/pull/2818 -[cargo/3000]: https://github.com/rust-lang/cargo/pull/3000 -[cargo/3021]: https://github.com/rust-lang/cargo/pull/3021 -[cargo/3038]: https://github.com/rust-lang/cargo/pull/3038 -[cargo/3060]: https://github.com/rust-lang/cargo/pull/3060 -[cargo/3078]: https://github.com/rust-lang/cargo/pull/3078 -[cargo/3089]: https://github.com/rust-lang/cargo/pull/3089 -[cargo/3092]: https://github.com/rust-lang/cargo/pull/3092 -[cargo/3110]: https://github.com/rust-lang/cargo/pull/3110 -[cargo/3121]: https://github.com/rust-lang/cargo/pull/3121 -[cargo/3123]: https://github.com/rust-lang/cargo/pull/3123 -[cargo/3125]: https://github.com/rust-lang/cargo/pull/3125 -[cargo/3136]: https://github.com/rust-lang/cargo/pull/3136 -[cargo/3144]: https://github.com/rust-lang/cargo/pull/3144 -[cargo/3146]: https://github.com/rust-lang/cargo/pull/3146 -[cargo/3157]: https://github.com/rust-lang/cargo/pull/3157 -[cargo/3162]: https://github.com/rust-lang/cargo/pull/3162 -[cargo/3205]: https://github.com/rust-lang/cargo/pull/3205 -[cargo/3241]: https://github.com/rust-lang/cargo/pull/3241 -[cargo/3242]: https://github.com/rust-lang/cargo/pull/3242 -[rustup]: https://www.rustup.rs -[`checked_abs`]: https://doc.rust-lang.org/std/primitive.i32.html#method.checked_abs -[`wrapping_abs`]: https://doc.rust-lang.org/std/primitive.i32.html#method.wrapping_abs -[`overflowing_abs`]: https://doc.rust-lang.org/std/primitive.i32.html#method.overflowing_abs -[`RefCell::try_borrow`]: https://doc.rust-lang.org/std/cell/struct.RefCell.html#method.try_borrow -[`RefCell::try_borrow_mut`]: https://doc.rust-lang.org/std/cell/struct.RefCell.html#method.try_borrow_mut -[`SipHasher`]: https://doc.rust-lang.org/std/hash/struct.SipHasher.html -[`DefaultHasher`]: https://doc.rust-lang.org/std/collections/hash_map/struct.DefaultHasher.html - - Version 1.12.1 (2016-10-20) =========================== @@ -338,7 +81,7 @@ Diagnostics Most common editors supporting Rust have been updated to work with it. It was previously described [on the Rust blog] (https://blog.rust-lang.org/2016/08/10/Shape-of-errors-to-come.html). -* [In error descriptions, references are now described in plain english, +* [In error descriptions, references are now described in plain English, instead of as "&-ptr"] (https://github.com/rust-lang/rust/pull/35611) * [In error type descriptions, unknown numeric types are named `{integer}` or @@ -432,7 +175,7 @@ Libraries (https://github.com/rust-lang/rust/pull/34946) * [`hash_map::Entry`, `hash_map::VacantEntry` and `hash_map::OccupiedEntry` implement `Debug`] - (https://github.com/rust-lang/rust/pull/34946) + (https://github.com/rust-lang/rust/pull/34937) * [`btree_map::Entry`, `btree_map::VacantEntry` and `btree_map::OccupiedEntry` implement `Debug`] (https://github.com/rust-lang/rust/pull/34885) @@ -1169,7 +912,7 @@ Cargo Performance ----------- -* [The time complexity of comparing variables for equivalence during type +* [The time complexity of comparing variables for equivalence during type unification is reduced from _O_(_n_!) to _O_(_n_)][1.9tu]. This leads to major compilation time improvement in some scenarios. * [`ToString` is specialized for `str`, giving it the same performance diff --git a/configure b/configure index fd0397e5f8..85a3dd4b93 100755 --- a/configure +++ b/configure @@ -507,11 +507,16 @@ case $CFG_CPUTYPE in CFG_CPUTYPE=arm ;; - armv7l) + armv6l) CFG_CPUTYPE=arm CFG_OSTYPE="${CFG_OSTYPE}eabihf" ;; + armv7l) + CFG_CPUTYPE=armv7 + CFG_OSTYPE="${CFG_OSTYPE}eabihf" + ;; + aarch64) CFG_CPUTYPE=aarch64 ;; @@ -610,6 +615,7 @@ opt docs 1 "build standard library documentation" opt compiler-docs 0 "build compiler documentation" opt optimize-tests 1 "build tests with optimizations" opt debuginfo-tests 0 "build tests with debugger metadata" +opt quiet-tests 0 "enable quieter output when running tests" opt libcpp 1 "build llvm with libc++ instead of libstdc++ when using clang" opt llvm-assertions 0 "build LLVM with assertions" opt debug-assertions 0 "build with debugging assertions" @@ -636,6 +642,7 @@ 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 debuginfo-lines 0 "build with line number debugger metadata" opt_nosave debug-jemalloc 0 "build jemalloc with --enable-debug --enable-fill" valopt localstatedir "/var/lib" "local state directory" @@ -645,7 +652,6 @@ valopt datadir "${CFG_PREFIX}/share" "install data" valopt infodir "${CFG_PREFIX}/share/info" "install additional info" valopt llvm-root "" "set LLVM root" valopt python "" "set path to python" -valopt nodejs "" "set path to nodejs" valopt jemalloc-root "" "set directory where libjemalloc_pic.a is located" valopt build "${DEFAULT_BUILD}" "GNUs ./configure syntax LLVM build triple" valopt android-cross-path "" "Android NDK standalone path (deprecated)" @@ -654,7 +660,12 @@ valopt arm-linux-androideabi-ndk "" "arm-linux-androideabi NDK standalone path" valopt armv7-linux-androideabi-ndk "" "armv7-linux-androideabi NDK standalone path" valopt aarch64-linux-android-ndk "" "aarch64-linux-android NDK standalone path" valopt nacl-cross-path "" "NaCl SDK path (Pepper Canary is recommended). Must be absolute!" -valopt musl-root "/usr/local" "MUSL root installation directory" +valopt musl-root "/usr/local" "MUSL root installation directory (deprecated)" +valopt musl-root-x86_64 "/usr/local" "x86_64-unknown-linux-musl install directory" +valopt musl-root-i686 "/usr/local" "i686-unknown-linux-musl install directory" +valopt musl-root-arm "/usr/local" "arm-unknown-linux-musleabi install directory" +valopt musl-root-armhf "/usr/local" "arm-unknown-linux-musleabihf install directory" +valopt musl-root-armv7 "/usr/local" "armv7-unknown-linux-musleabihf install directory" valopt extra-filename "" "Additional data that is hashed and passed to the -C extra-filename flag" if [ -e ${CFG_SRC_DIR}.git ] @@ -717,8 +728,27 @@ case "$CFG_RELEASE_CHANNEL" in nightly ) msg "overriding settings for $CFG_RELEASE_CHANNEL" CFG_ENABLE_LLVM_ASSERTIONS=1 + + # FIXME(#37364) shouldn't have to disable this on windows-gnu + case "$CFG_BUILD" in + *-pc-windows-gnu) + ;; + *) + CFG_ENABLE_DEBUGINFO_LINES=1 + ;; + esac ;; - dev | beta | stable) + beta | stable) + msg "overriding settings for $CFG_RELEASE_CHANNEL" + case "$CFG_BUILD" in + *-pc-windows-gnu) + ;; + *) + CFG_ENABLE_DEBUGINFO_LINES=1 + ;; + esac + ;; + dev) ;; *) err "release channel must be 'dev', 'nightly', 'beta' or 'stable'" @@ -748,6 +778,7 @@ if [ -n "$CFG_DISABLE_OPTIMIZE_LLVM" ]; then putvar CFG_DISABLE_OPTIMIZE_LLVM; f 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_DEBUGINFO_LINES" ]; then putvar CFG_ENABLE_DEBUGINFO_LINES; fi if [ -n "$CFG_ENABLE_DEBUG_JEMALLOC" ]; then putvar CFG_ENABLE_DEBUG_JEMALLOC; fi step_msg "looking for build programs" @@ -762,9 +793,6 @@ if [ $(echo $python_version | grep -c '^Python 2\.7') -ne 1 ]; then err "Found $python_version, but Python 2.7 is required" fi -# Checking for node, but not required -probe CFG_NODEJS nodejs node - # If we have no git directory then we are probably a tarball distribution # and shouldn't attempt to load submodules if [ ! -e ${CFG_SRC_DIR}.git ] @@ -840,13 +868,6 @@ then fi fi -if [ -n "$CFG_GDB" ] -then - # Store GDB's version - CFG_GDB_VERSION=$($CFG_GDB --version 2>/dev/null | head -1) - putvar CFG_GDB_VERSION -fi - if [ -n "$CFG_LLDB" ] then # Store LLDB's version @@ -1216,14 +1237,6 @@ do fi ;; - - x86_64-*-musl | arm-*-musleabi) - if [ ! -f $CFG_MUSL_ROOT/lib/libc.a ] - then - err "musl libc $CFG_MUSL_ROOT/lib/libc.a not found" - fi - ;; - *-msvc) # There are three builds of cmake on windows: MSVC, MinGW and Cygwin # The Cygwin build does not have generators for Visual Studio, so @@ -1642,8 +1655,8 @@ do ("ccache gcc") LLVM_CXX_32="ccache" LLVM_CC_32="ccache" - LLVM_CXX_32_ARG1="clang++" - LLVM_CC_32_ARG1="clang" + LLVM_CXX_32_ARG1="g++" + LLVM_CC_32_ARG1="gcc" LLVM_CXX_64="ccache" LLVM_CC_64="ccache" @@ -1768,7 +1781,7 @@ do CMAKE_ARGS="$CMAKE_ARGS -DLLVM_ENABLE_ASSERTIONS=ON" fi - CMAKE_ARGS="$CMAKE_ARGS -DLLVM_TARGETS_TO_BUILD='X86;ARM;AArch64;Mips;PowerPC;SystemZ'" + CMAKE_ARGS="$CMAKE_ARGS -DLLVM_TARGETS_TO_BUILD='X86;ARM;AArch64;Mips;PowerPC;SystemZ;JSBackend'" CMAKE_ARGS="$CMAKE_ARGS -G '$CFG_CMAKE_GENERATOR'" CMAKE_ARGS="$CMAKE_ARGS $CFG_LLVM_SRC_DIR" diff --git a/mk/cfg/aarch64-unknown-fuchsia.mk b/mk/cfg/aarch64-unknown-fuchsia.mk new file mode 100644 index 0000000000..34aee77ae2 --- /dev/null +++ b/mk/cfg/aarch64-unknown-fuchsia.mk @@ -0,0 +1 @@ +# rustbuild-only target diff --git a/mk/cfg/wasm32-unknown-emscripten.mk b/mk/cfg/wasm32-unknown-emscripten.mk new file mode 100644 index 0000000000..997bdfbf03 --- /dev/null +++ b/mk/cfg/wasm32-unknown-emscripten.mk @@ -0,0 +1,24 @@ +# wasm32-unknown-emscripten configuration +CC_wasm32-unknown-emscripten=emcc +CXX_wasm32-unknown-emscripten=em++ +CPP_wasm32-unknown-emscripten=$(CPP) +AR_wasm32-unknown-emscripten=emar +CFG_LIB_NAME_wasm32-unknown-emscripten=lib$(1).so +CFG_STATIC_LIB_NAME_wasm32-unknown-emscripten=lib$(1).a +CFG_LIB_GLOB_wasm32-unknown-emscripten=lib$(1)-*.so +CFG_LIB_DSYM_GLOB_wasm32-unknown-emscripten=lib$(1)-*.dylib.dSYM +CFG_JEMALLOC_CFLAGS_wasm32-unknown-emscripten := -m32 $(CFLAGS) +CFG_GCCISH_CFLAGS_wasm32-unknown-emscripten := -g -fPIC -m32 -s BINARYEN=1 $(CFLAGS) +CFG_GCCISH_CXXFLAGS_wasm32-unknown-emscripten := -fno-rtti -s BINARYEN=1 $(CXXFLAGS) +CFG_GCCISH_LINK_FLAGS_wasm32-unknown-emscripten := -shared -fPIC -ldl -pthread -lrt -g -m32 -s BINARYEN=1 +CFG_GCCISH_DEF_FLAG_wasm32-unknown-emscripten := -Wl,--export-dynamic,--dynamic-list= +CFG_LLC_FLAGS_wasm32-unknown-emscripten := +CFG_INSTALL_NAME_wasm32-unknown-emscripten = +CFG_EXE_SUFFIX_wasm32-unknown-emscripten = +CFG_WINDOWSY_wasm32-unknown-emscripten := +CFG_UNIXY_wasm32-unknown-emscripten := 1 +CFG_LDPATH_wasm32-unknown-emscripten := +CFG_RUN_wasm32-unknown-emscripten=$(2) +CFG_RUN_TARG_wasm32-unknown-emscripten=$(call CFG_RUN_wasm32-unknown-emscripten,,$(2)) +CFG_GNU_TRIPLE_wasm32-unknown-emscripten := wasm32-unknown-emscripten +CFG_DISABLE_JEMALLOC_wasm32-unknown-emscripten := 1 diff --git a/mk/cfg/x86_64-unknown-fuchsia.mk b/mk/cfg/x86_64-unknown-fuchsia.mk new file mode 100644 index 0000000000..34aee77ae2 --- /dev/null +++ b/mk/cfg/x86_64-unknown-fuchsia.mk @@ -0,0 +1 @@ +# rustbuild-only target diff --git a/mk/crates.mk b/mk/crates.mk index 86bb3a8ca0..25192bfd27 100644 --- a/mk/crates.mk +++ b/mk/crates.mk @@ -59,9 +59,9 @@ RUSTC_CRATES := rustc rustc_typeck rustc_mir rustc_borrowck rustc_resolve rustc_ rustc_trans rustc_back rustc_llvm rustc_privacy rustc_lint \ rustc_data_structures rustc_platform_intrinsics rustc_errors \ rustc_plugin rustc_metadata rustc_passes rustc_save_analysis \ - rustc_const_eval rustc_const_math rustc_incremental rustc_macro -HOST_CRATES := syntax syntax_ext proc_macro syntax_pos $(RUSTC_CRATES) rustdoc fmt_macros \ - flate arena graphviz log serialize + rustc_const_eval rustc_const_math rustc_incremental proc_macro +HOST_CRATES := syntax syntax_ext proc_macro_tokens proc_macro_plugin syntax_pos $(RUSTC_CRATES) \ + rustdoc fmt_macros flate arena graphviz log serialize TOOLS := compiletest rustdoc rustc rustbook error_index_generator DEPS_core := @@ -101,9 +101,10 @@ DEPS_term := std DEPS_test := std getopts term native:rust_test_helpers DEPS_syntax := std term serialize log arena libc rustc_bitflags rustc_unicode rustc_errors syntax_pos -DEPS_syntax_ext := syntax syntax_pos rustc_errors fmt_macros rustc_macro -DEPS_proc_macro := syntax syntax_pos rustc_plugin log +DEPS_syntax_ext := syntax syntax_pos rustc_errors fmt_macros proc_macro DEPS_syntax_pos := serialize +DEPS_proc_macro_tokens := syntax syntax_pos log +DEPS_proc_macro_plugin := syntax syntax_pos rustc_plugin log proc_macro_tokens DEPS_rustc_const_math := std syntax log serialize DEPS_rustc_const_eval := rustc_const_math rustc syntax log serialize \ @@ -118,15 +119,15 @@ DEPS_rustc_data_structures := std log serialize libc DEPS_rustc_driver := arena flate getopts graphviz libc rustc rustc_back rustc_borrowck \ rustc_typeck rustc_mir rustc_resolve log syntax serialize rustc_llvm \ rustc_trans rustc_privacy rustc_lint rustc_plugin \ - rustc_metadata syntax_ext proc_macro \ + rustc_metadata syntax_ext proc_macro_plugin \ rustc_passes rustc_save_analysis rustc_const_eval \ - rustc_incremental syntax_pos rustc_errors rustc_macro + rustc_incremental syntax_pos rustc_errors proc_macro rustc_data_structures DEPS_rustc_errors := log libc serialize syntax_pos DEPS_rustc_lint := rustc log syntax syntax_pos rustc_const_eval DEPS_rustc_llvm := native:rustllvm libc std rustc_bitflags -DEPS_rustc_macro := std syntax +DEPS_proc_macro := std syntax DEPS_rustc_metadata := rustc syntax syntax_pos rustc_errors rustc_const_math \ - rustc_macro syntax_ext + proc_macro syntax_ext DEPS_rustc_passes := syntax syntax_pos rustc core rustc_const_eval rustc_errors DEPS_rustc_mir := rustc syntax syntax_pos rustc_const_math rustc_const_eval rustc_bitflags DEPS_rustc_resolve := arena rustc log syntax syntax_pos rustc_errors diff --git a/mk/llvm.mk b/mk/llvm.mk index d6f812049e..5a91f5fcaa 100644 --- a/mk/llvm.mk +++ b/mk/llvm.mk @@ -36,22 +36,27 @@ endif # If CFG_LLVM_ROOT is defined then we don't build LLVM ourselves ifeq ($(CFG_LLVM_ROOT),) -LLVM_STAMP_$(1) = $$(CFG_LLVM_BUILD_DIR_$(1))/llvm-auto-clean-stamp +LLVM_STAMP_$(1) = $(S)src/rustllvm/llvm-auto-clean-trigger LLVM_DONE_$(1) = $$(CFG_LLVM_BUILD_DIR_$(1))/llvm-finished-building $$(LLVM_CONFIG_$(1)): $$(LLVM_DONE_$(1)) -$$(LLVM_DONE_$(1)): $$(LLVM_DEPS_TARGET_$(1)) $$(LLVM_STAMP_$(1)) - @$$(call E, cmake: llvm) ifneq ($$(CFG_NINJA),) - $$(Q)$$(CFG_NINJA) -C $$(CFG_LLVM_BUILD_DIR_$(1)) +BUILD_LLVM_$(1) := $$(CFG_NINJA) -C $$(CFG_LLVM_BUILD_DIR_$(1)) else ifeq ($$(findstring msvc,$(1)),msvc) - $$(Q)$$(CFG_CMAKE) --build $$(CFG_LLVM_BUILD_DIR_$(1)) \ - --config $$(LLVM_BUILD_CONFIG_MODE) +BUILD_LLVM_$(1) := $$(CFG_CMAKE) --build $$(CFG_LLVM_BUILD_DIR_$(1)) \ + --config $$(LLVM_BUILD_CONFIG_MODE) else - $$(Q)$$(MAKE) -C $$(CFG_LLVM_BUILD_DIR_$(1)) +BUILD_LLVM_$(1) := $$(MAKE) -C $$(CFG_LLVM_BUILD_DIR_$(1)) endif - $$(Q)touch $$@ + +$$(LLVM_DONE_$(1)): $$(LLVM_DEPS_TARGET_$(1)) $$(LLVM_STAMP_$(1)) + @$$(call E, cmake: llvm) + $$(Q)if ! cmp $$(LLVM_STAMP_$(1)) $$(LLVM_DONE_$(1)); then \ + $$(MAKE) clean-llvm$(1); \ + $$(BUILD_LLVM_$(1)); \ + fi + $$(Q)cp $$(LLVM_STAMP_$(1)) $$@ ifneq ($$(CFG_NINJA),) clean-llvm$(1): @@ -75,17 +80,6 @@ endif $$(LLVM_AR_$(1)): $$(LLVM_CONFIG_$(1)) -# This is used to independently force an LLVM clean rebuild -# when we changed something not otherwise captured by builtin -# dependencies. In these cases, commit a change that touches -# the stamp in the source dir. -$$(LLVM_STAMP_$(1)): $$(S)src/rustllvm/llvm-auto-clean-trigger - @$$(call E, make: cleaning llvm) - $$(Q)touch $$@.start_time - $$(Q)$$(MAKE) clean-llvm$(1) - @$$(call E, make: done cleaning llvm) - touch -r $$@.start_time $$@ && rm $$@.start_time - ifeq ($$(CFG_ENABLE_LLVM_STATIC_STDCPP),1) LLVM_STDCPP_RUSTFLAGS_$(1) = -L "$$(dir $$(shell $$(CC_$(1)) $$(CFG_GCCISH_CFLAGS_$(1)) \ -print-file-name=lib$(CFG_STDCPP_NAME).a))" diff --git a/mk/main.mk b/mk/main.mk index 45c085c27c..fd0464aab8 100644 --- a/mk/main.mk +++ b/mk/main.mk @@ -13,12 +13,12 @@ ###################################################################### # The version number -CFG_RELEASE_NUM=1.13.0 +CFG_RELEASE_NUM=1.14.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=.3 +CFG_PRERELEASE_VERSION=.5 ifeq ($(CFG_RELEASE_CHANNEL),stable) # This is the normal semver version string, e.g. "0.12.0", "0.12.0-nightly" @@ -53,11 +53,12 @@ endif # versions in the same place CFG_FILENAME_EXTRA=$(shell printf '%s' $(CFG_RELEASE)$(CFG_EXTRA_FILENAME) | $(CFG_HASH_COMMAND)) -# If local-rust is the same as the current version, then force a local-rebuild +# If local-rust is the same major.minor as the current version, then force a local-rebuild ifdef CFG_ENABLE_LOCAL_RUST -ifeq ($(CFG_RELEASE),\ - $(shell $(S)src/etc/local_stage0.sh --print-rustc-release $(CFG_LOCAL_RUST_ROOT))) - CFG_INFO := $(info cfg: auto-detected local-rebuild $(CFG_RELEASE)) +SEMVER_PREFIX=$(shell echo $(CFG_RELEASE_NUM) | grep -E -o '^[[:digit:]]+\.[[:digit:]]+') +LOCAL_RELEASE=$(shell $(S)src/etc/local_stage0.sh --print-rustc-release $(CFG_LOCAL_RUST_ROOT)) +ifneq (,$(filter $(SEMVER_PREFIX).%,$(LOCAL_RELEASE))) + CFG_INFO := $(info cfg: auto-detected local-rebuild using $(LOCAL_RELEASE)) CFG_ENABLE_LOCAL_REBUILD = 1 endif endif @@ -141,6 +142,9 @@ endif ifdef CFG_ENABLE_DEBUGINFO $(info cfg: enabling debuginfo (CFG_ENABLE_DEBUGINFO)) CFG_RUSTC_FLAGS += -g +else ifdef CFG_ENABLE_DEBUGINFO_LINES + $(info cfg: enabling line number debuginfo (CFG_ENABLE_DEBUGINFO_LINES)) + CFG_RUSTC_FLAGS += -Cdebuginfo=1 endif ifdef SAVE_TEMPS @@ -281,7 +285,7 @@ endif # LLVM macros ###################################################################### -LLVM_OPTIONAL_COMPONENTS=x86 arm aarch64 mips powerpc pnacl systemz +LLVM_OPTIONAL_COMPONENTS=x86 arm aarch64 mips powerpc pnacl systemz jsbackend LLVM_REQUIRED_COMPONENTS=ipo bitreader bitwriter linker asmparser mcjit \ interpreter instrumentation @@ -376,7 +380,7 @@ endif # FIXME: Transitionary measure to bootstrap using the old bootstrap logic. # Remove this once the bootstrap compiler uses the new login in Issue #36548. -export RUSTC_BOOTSTRAP_KEY=5c6cf767 +export RUSTC_BOOTSTRAP_KEY=62b3e239 ###################################################################### # Per-stage targets and runner diff --git a/mk/tests.mk b/mk/tests.mk index fc1f4b5561..f3d8f0387b 100644 --- a/mk/tests.mk +++ b/mk/tests.mk @@ -632,6 +632,7 @@ endif # is a separate choice from whether to pass `-g` when building the # compiler and standard library themselves. CTEST_RUSTC_FLAGS := $$(subst -g,,$$(CTEST_RUSTC_FLAGS)) +CTEST_RUSTC_FLAGS := $$(subst -Cdebuginfo=1,,$$(CTEST_RUSTC_FLAGS)) ifdef CFG_ENABLE_DEBUGINFO_TESTS CTEST_RUSTC_FLAGS += -g endif @@ -647,7 +648,7 @@ CTEST_COMMON_ARGS$(1)-T-$(2)-H-$(3) = \ --host $(3) \ --docck-python $$(CFG_PYTHON) \ --lldb-python $$(CFG_LLDB_PYTHON) \ - --gdb-version="$(CFG_GDB_VERSION)" \ + --gdb="$(CFG_GDB)" \ --lldb-version="$(CFG_LLDB_VERSION)" \ --llvm-version="$$(LLVM_VERSION_$(3))" \ --android-cross-path=$(CFG_ARM_LINUX_ANDROIDEABI_NDK) \ diff --git a/src/bootstrap/Cargo.lock b/src/bootstrap/Cargo.lock deleted file mode 100644 index 36b94e4ebe..0000000000 --- a/src/bootstrap/Cargo.lock +++ /dev/null @@ -1,180 +0,0 @@ -[root] -name = "bootstrap" -version = "0.0.0" -dependencies = [ - "build_helper 0.1.0", - "cmake 0.1.17 (registry+https://github.com/rust-lang/crates.io-index)", - "filetime 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)", - "gcc 0.3.31 (git+https://github.com/alexcrichton/gcc-rs)", - "getopts 0.2.14 (registry+https://github.com/rust-lang/crates.io-index)", - "kernel32-sys 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.10 (registry+https://github.com/rust-lang/crates.io-index)", - "md5 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", - "num_cpus 0.2.11 (registry+https://github.com/rust-lang/crates.io-index)", - "regex 0.1.73 (registry+https://github.com/rust-lang/crates.io-index)", - "rustc-serialize 0.3.19 (registry+https://github.com/rust-lang/crates.io-index)", - "toml 0.1.28 (registry+https://github.com/rust-lang/crates.io-index)", - "winapi 0.2.6 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "aho-corasick" -version = "0.5.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "memchr 0.1.11 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "build_helper" -version = "0.1.0" - -[[package]] -name = "cmake" -version = "0.1.17" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "gcc 0.3.31 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "filetime" -version = "0.1.10" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "libc 0.2.10 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "gcc" -version = "0.3.31" -source = "git+https://github.com/alexcrichton/gcc-rs#b8e2400883f1a2749b323354dad372cdd1c838c7" - -[[package]] -name = "gcc" -version = "0.3.31" -source = "registry+https://github.com/rust-lang/crates.io-index" - -[[package]] -name = "getopts" -version = "0.2.14" -source = "registry+https://github.com/rust-lang/crates.io-index" - -[[package]] -name = "kernel32-sys" -version = "0.2.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "winapi 0.2.6 (registry+https://github.com/rust-lang/crates.io-index)", - "winapi-build 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "libc" -version = "0.2.10" -source = "registry+https://github.com/rust-lang/crates.io-index" - -[[package]] -name = "md5" -version = "0.1.1" -source = "registry+https://github.com/rust-lang/crates.io-index" - -[[package]] -name = "memchr" -version = "0.1.11" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "libc 0.2.10 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "num_cpus" -version = "0.2.11" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "libc 0.2.10 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "regex" -version = "0.1.73" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "aho-corasick 0.5.2 (registry+https://github.com/rust-lang/crates.io-index)", - "memchr 0.1.11 (registry+https://github.com/rust-lang/crates.io-index)", - "regex-syntax 0.3.4 (registry+https://github.com/rust-lang/crates.io-index)", - "thread_local 0.2.6 (registry+https://github.com/rust-lang/crates.io-index)", - "utf8-ranges 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "regex-syntax" -version = "0.3.4" -source = "registry+https://github.com/rust-lang/crates.io-index" - -[[package]] -name = "rustc-serialize" -version = "0.3.19" -source = "registry+https://github.com/rust-lang/crates.io-index" - -[[package]] -name = "thread-id" -version = "2.0.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "kernel32-sys 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.10 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "thread_local" -version = "0.2.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "thread-id 2.0.0 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "toml" -version = "0.1.28" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "rustc-serialize 0.3.19 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "utf8-ranges" -version = "0.1.3" -source = "registry+https://github.com/rust-lang/crates.io-index" - -[[package]] -name = "winapi" -version = "0.2.6" -source = "registry+https://github.com/rust-lang/crates.io-index" - -[[package]] -name = "winapi-build" -version = "0.1.1" -source = "registry+https://github.com/rust-lang/crates.io-index" - -[metadata] -"checksum aho-corasick 0.5.2 (registry+https://github.com/rust-lang/crates.io-index)" = "2b3fb52b09c1710b961acb35390d514be82e4ac96a9969a8e38565a29b878dc9" -"checksum cmake 0.1.17 (registry+https://github.com/rust-lang/crates.io-index)" = "dfcf5bcece56ef953b8ea042509e9dcbdfe97820b7e20d86beb53df30ed94978" -"checksum filetime 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)" = "5363ab8e4139b8568a6237db5248646e5a8a2f89bd5ccb02092182b11fd3e922" -"checksum gcc 0.3.31 (git+https://github.com/alexcrichton/gcc-rs)" = "" -"checksum gcc 0.3.31 (registry+https://github.com/rust-lang/crates.io-index)" = "cfe877476e53690ebb0ce7325d0bf43e198d9500291b54b3c65e518de5039b07" -"checksum getopts 0.2.14 (registry+https://github.com/rust-lang/crates.io-index)" = "d9047cfbd08a437050b363d35ef160452c5fe8ea5187ae0a624708c91581d685" -"checksum kernel32-sys 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "7507624b29483431c0ba2d82aece8ca6cdba9382bff4ddd0f7490560c056098d" -"checksum libc 0.2.10 (registry+https://github.com/rust-lang/crates.io-index)" = "55f3730be7e803cf350d32061958171731c2395831fbd67a61083782808183e0" -"checksum md5 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "a5539a8dee9b4ae308c9c406a379838b435a8f2c84cf9fedc6d5a576be9888db" -"checksum memchr 0.1.11 (registry+https://github.com/rust-lang/crates.io-index)" = "d8b629fb514376c675b98c1421e80b151d3817ac42d7c667717d282761418d20" -"checksum num_cpus 0.2.11 (registry+https://github.com/rust-lang/crates.io-index)" = "51fedae97a05f7353612fe017ab705a37e6db8f4d67c5c6fe739a9e70d6eed09" -"checksum regex 0.1.73 (registry+https://github.com/rust-lang/crates.io-index)" = "56b7ee9f764ecf412c6e2fff779bca4b22980517ae335a21aeaf4e32625a5df2" -"checksum regex-syntax 0.3.4 (registry+https://github.com/rust-lang/crates.io-index)" = "31040aad7470ad9d8c46302dcffba337bb4289ca5da2e3cd6e37b64109a85199" -"checksum rustc-serialize 0.3.19 (registry+https://github.com/rust-lang/crates.io-index)" = "6159e4e6e559c81bd706afe9c8fd68f547d3e851ce12e76b1de7914bab61691b" -"checksum thread-id 2.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "a9539db560102d1cef46b8b78ce737ff0bb64e7e18d35b2a5688f7d097d0ff03" -"checksum thread_local 0.2.6 (registry+https://github.com/rust-lang/crates.io-index)" = "55dd963dbaeadc08aa7266bf7f91c3154a7805e32bb94b820b769d2ef3b4744d" -"checksum toml 0.1.28 (registry+https://github.com/rust-lang/crates.io-index)" = "fcd27a04ca509aff336ba5eb2abc58d456f52c4ff64d9724d88acb85ead560b6" -"checksum utf8-ranges 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)" = "a1ca13c08c41c9c3e04224ed9ff80461d97e121589ff27c753a16cb10830ae0f" -"checksum winapi 0.2.6 (registry+https://github.com/rust-lang/crates.io-index)" = "4dfaaa8fbdaa618fa6914b59b2769d690dd7521920a18d84b42d254678dd5fd4" -"checksum winapi-build 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "2d315eee3b34aca4797b2da6b13ed88266e6d612562a0c46390af8299fc699bc" diff --git a/src/bootstrap/Cargo.toml b/src/bootstrap/Cargo.toml index b19545590b..9d44ca033e 100644 --- a/src/bootstrap/Cargo.toml +++ b/src/bootstrap/Cargo.toml @@ -27,9 +27,10 @@ num_cpus = "0.2" toml = "0.1" getopts = "0.2" rustc-serialize = "0.3" -winapi = "0.2" -kernel32-sys = "0.2" -gcc = { git = "https://github.com/alexcrichton/gcc-rs" } +gcc = "0.3.36" libc = "0.2" md5 = "0.1" -regex = "0.1.73" + +[target.'cfg(windows)'.dependencies] +winapi = "0.2" +kernel32-sys = "0.2" diff --git a/src/bootstrap/README.md b/src/bootstrap/README.md index 57d644d635..f73f41ffae 100644 --- a/src/bootstrap/README.md +++ b/src/bootstrap/README.md @@ -10,24 +10,72 @@ system. ## Using rustbuild -When configuring Rust via `./configure`, pass the following to enable building -via this build system: +The rustbuild build system has a primary entry point, a top level `x.py` script: ``` -./configure --enable-rustbuild -make +python ./x.py build ``` -Afterwards the `Makefile` which is generated will have a few commands like -`make check`, `make tidy`, etc. For finer-grained control, the -`bootstrap.py` entry point can be used: +Note that if you're on Unix you should be able to execute the script directly: ``` -python src/bootstrap/bootstrap.py +./x.py build ``` -This accepts a number of options like `--stage` and `--step` which can configure -what's actually being done. +The script accepts commands, flags, and filters to determine what to do: + +* `build` - a general purpose command for compiling code. Alone `build` will + bootstrap the entire compiler, and otherwise arguments passed indicate what to + build. For example: + + ``` + # build the whole compiler + ./x.py build + + # build the stage1 compier + ./x.py build --stage 1 + + # build stage0 libstd + ./x.py build --stage 0 src/libstd + + # build a particular crate in stage0 + ./x.py build --stage 0 src/libtest + ``` + +* `test` - a command for executing unit tests. Like the `build` command this + will execute the entire test suite by default, and otherwise it can be used to + select which test suite is run: + + ``` + # run all unit tests + ./x.py test + + # execute the run-pass test suite + ./x.py test src/test/run-pass + + # execute only some tests in the run-pass test suite + ./x.py test src/test/run-pass --filter my-filter + + # execute tests in the standard library in stage0 + ./x.py test --stage 0 src/libstd + + # execute all doc tests + ./x.py test src/doc + ``` + +* `doc` - a command for building documentation. Like above can take arguments + for what to document. + +If you're more used to `./configure` and `make`, however, then you can also +configure the build system to use rustbuild instead of the old makefiles: + +``` +./configure --enable-rustbuild +make +``` + +Afterwards the `Makefile` which is generated will have a few commands like +`make check`, `make tidy`, etc. ## Configuring rustbuild @@ -47,7 +95,7 @@ being invoked manually (via the python script). The rustbuild build system goes through a few phases to actually build the compiler. What actually happens when you invoke rustbuild is: -1. The entry point script, `src/bootstrap/bootstrap.py` is run. This script is +1. The entry point script, `x.py` is run. This script is responsible for downloading the stage0 compiler/Cargo binaries, and it then compiles the build system itself (this folder). Finally, it then invokes the actual `bootstrap` binary build system. diff --git a/src/bootstrap/bin/rustc.rs b/src/bootstrap/bin/rustc.rs index a70a15b383..879eca60cc 100644 --- a/src/bootstrap/bin/rustc.rs +++ b/src/bootstrap/bin/rustc.rs @@ -36,8 +36,9 @@ fn main() { let args = env::args_os().skip(1).collect::>(); // Detect whether or not we're a build script depending on whether --target // is passed (a bit janky...) - let target = args.windows(2).find(|w| &*w[0] == "--target") - .and_then(|w| w[1].to_str()); + let target = args.windows(2) + .find(|w| &*w[0] == "--target") + .and_then(|w| w[1].to_str()); let version = args.iter().find(|w| &**w == "-vV"); // Build scripts always use the snapshot compiler which is guaranteed to be @@ -64,9 +65,10 @@ fn main() { let mut cmd = Command::new(rustc); cmd.args(&args) - .arg("--cfg").arg(format!("stage{}", stage)) - .env(bootstrap::util::dylib_path_var(), - env::join_paths(&dylib_path).unwrap()); + .arg("--cfg") + .arg(format!("stage{}", stage)) + .env(bootstrap::util::dylib_path_var(), + env::join_paths(&dylib_path).unwrap()); if let Some(target) = target { // The stage0 compiler has a special sysroot distinct from what we @@ -101,11 +103,9 @@ fn main() { // This... is a bit of a hack how we detect this. Ideally this // information should be encoded in the crate I guess? Would likely // require an RFC amendment to RFC 1513, however. - let is_panic_abort = args.windows(2).any(|a| { - &*a[0] == "--crate-name" && &*a[1] == "panic_abort" - }); - // FIXME(stage0): remove this `stage != "0"` condition - if is_panic_abort && stage != "0" { + let is_panic_abort = args.windows(2) + .any(|a| &*a[0] == "--crate-name" && &*a[1] == "panic_abort"); + if is_panic_abort { cmd.arg("-C").arg("panic=abort"); } @@ -113,9 +113,11 @@ fn main() { // code. if env::var("RUSTC_DEBUGINFO") == Ok("true".to_string()) { cmd.arg("-g"); + } else if env::var("RUSTC_DEBUGINFO_LINES") == Ok("true".to_string()) { + cmd.arg("-Cdebuginfo=1"); } let debug_assertions = match env::var("RUSTC_DEBUG_ASSERTIONS") { - Ok(s) => if s == "true" {"y"} else {"n"}, + Ok(s) => if s == "true" { "y" } else { "n" }, Err(..) => "n", }; cmd.arg("-C").arg(format!("debug-assertions={}", debug_assertions)); diff --git a/src/bootstrap/bin/rustdoc.rs b/src/bootstrap/bin/rustdoc.rs index 658ff358d6..67358e540d 100644 --- a/src/bootstrap/bin/rustdoc.rs +++ b/src/bootstrap/bin/rustdoc.rs @@ -29,10 +29,12 @@ fn main() { let mut cmd = Command::new(rustdoc); cmd.args(&args) - .arg("--cfg").arg(format!("stage{}", stage)) - .arg("--cfg").arg("dox") - .env(bootstrap::util::dylib_path_var(), - env::join_paths(&dylib_path).unwrap()); + .arg("--cfg") + .arg(format!("stage{}", stage)) + .arg("--cfg") + .arg("dox") + .env(bootstrap::util::dylib_path_var(), + env::join_paths(&dylib_path).unwrap()); std::process::exit(match cmd.status() { Ok(s) => s.code().unwrap_or(1), Err(e) => panic!("\n\nfailed to run {:?}: {}\n\n", cmd, e), diff --git a/src/bootstrap/bootstrap.py b/src/bootstrap/bootstrap.py index 2c2260a8e6..63feea1057 100644 --- a/src/bootstrap/bootstrap.py +++ b/src/bootstrap/bootstrap.py @@ -344,6 +344,22 @@ class RustBuild(object): ostype += 'eabihf' elif cputype == 'aarch64': cputype = 'aarch64' + elif cputype == 'mips': + if sys.byteorder == 'big': + cputype = 'mips' + elif sys.byteorder == 'little': + cputype = 'mipsel' + else: + raise ValueError('unknown byteorder: ' + sys.byteorder) + elif cputype == 'mips64': + if sys.byteorder == 'big': + cputype = 'mips64' + elif sys.byteorder == 'little': + cputype = 'mips64el' + else: + raise ValueError('unknown byteorder: ' + sys.byteorder) + # only the n64 ABI is supported, indicate it + ostype += 'abi64' elif cputype in {'powerpc', 'ppc', 'ppc64'}: cputype = 'powerpc' elif cputype in {'amd64', 'x86_64', 'x86-64', 'x64'}: @@ -399,12 +415,10 @@ def main(): # Run the bootstrap args = [os.path.join(rb.build_dir, "bootstrap/debug/bootstrap")] - args.append('--src') - args.append(rb.rust_root) - args.append('--build') - args.append(rb.build) args.extend(sys.argv[1:]) env = os.environ.copy() + env["BUILD"] = rb.build + env["SRC"] = rb.rust_root env["BOOTSTRAP_PARENT_ID"] = str(os.getpid()) rb.run(args, env) diff --git a/src/bootstrap/check.rs b/src/bootstrap/check.rs index 603a5ce752..611630c573 100644 --- a/src/bootstrap/check.rs +++ b/src/bootstrap/check.rs @@ -13,9 +13,9 @@ //! This file implements the various regression test suites that we execute on //! our CI. +use std::collections::HashSet; use std::env; -use std::fs::{self, File}; -use std::io::prelude::*; +use std::fs; use std::path::{PathBuf, Path}; use std::process::Command; @@ -108,6 +108,10 @@ pub fn compiletest(build: &Build, cmd.arg("--host").arg(compiler.host); cmd.arg("--llvm-filecheck").arg(build.llvm_filecheck(&build.config.build)); + if let Some(nodejs) = build.config.nodejs.as_ref() { + cmd.arg("--nodejs").arg(nodejs); + } + let mut flags = vec!["-Crpath".to_string()]; if build.config.rust_optimize_tests { flags.push("-O".to_string()); @@ -139,8 +143,8 @@ pub fn compiletest(build: &Build, cmd.arg("--lldb-python").arg(python_default); } - if let Some(ref vers) = build.gdb_version { - cmd.arg("--gdb-version").arg(vers); + if let Some(ref gdb) = build.config.gdb { + cmd.arg("--gdb").arg(gdb); } if let Some(ref vers) = build.lldb_version { cmd.arg("--lldb-version").arg(vers); @@ -152,12 +156,16 @@ pub fn compiletest(build: &Build, let llvm_version = output(Command::new(&llvm_config).arg("--version")); cmd.arg("--llvm-version").arg(llvm_version); - cmd.args(&build.flags.args); + cmd.args(&build.flags.cmd.test_args()); if build.config.verbose || build.flags.verbose { cmd.arg("--verbose"); } + if build.config.quiet_tests { + cmd.arg("--quiet"); + } + // Only pass correct values for these flags for the `run-make` suite as it // requires that a C++ compiler was configured which isn't always the case. if suite == "run-make" { @@ -248,7 +256,13 @@ fn markdown_test(build: &Build, compiler: &Compiler, markdown: &Path) { build.add_rustc_lib_path(compiler, &mut cmd); cmd.arg("--test"); cmd.arg(markdown); - cmd.arg("--test-args").arg(build.flags.args.join(" ")); + + let mut test_args = build.flags.cmd.test_args().join(" "); + if build.config.quiet_tests { + test_args.push_str(" --quiet"); + } + cmd.arg("--test-args").arg(test_args); + build.run(&mut cmd); } @@ -259,56 +273,58 @@ fn markdown_test(build: &Build, compiler: &Compiler, markdown: &Path) { /// It essentially is the driver for running `cargo test`. /// /// Currently this runs all tests for a DAG by passing a bunch of `-p foo` -/// arguments, and those arguments are discovered from `Cargo.lock`. +/// arguments, and those arguments are discovered from `cargo metadata`. pub fn krate(build: &Build, compiler: &Compiler, target: &str, - mode: Mode) { - let (name, path, features) = match mode { - Mode::Libstd => ("libstd", "src/rustc/std_shim", build.std_features()), - Mode::Libtest => ("libtest", "src/rustc/test_shim", String::new()), - Mode::Librustc => ("librustc", "src/rustc", build.rustc_features()), + mode: Mode, + krate: Option<&str>) { + let (name, path, features, root) = match mode { + Mode::Libstd => { + ("libstd", "src/rustc/std_shim", build.std_features(), "std_shim") + } + Mode::Libtest => { + ("libtest", "src/rustc/test_shim", String::new(), "test_shim") + } + Mode::Librustc => { + ("librustc", "src/rustc", build.rustc_features(), "rustc-main") + } _ => panic!("can only test libraries"), }; println!("Testing {} stage{} ({} -> {})", name, compiler.stage, compiler.host, target); // Build up the base `cargo test` command. + // + // Pass in some standard flags then iterate over the graph we've discovered + // in `cargo metadata` with the maps above and figure out what `-p` + // arguments need to get passed. let mut cargo = build.cargo(compiler, mode, target, "test"); cargo.arg("--manifest-path") .arg(build.src.join(path).join("Cargo.toml")) .arg("--features").arg(features); - // Generate a list of `-p` arguments to pass to the `cargo test` invocation - // by crawling the corresponding Cargo.lock file. - let lockfile = build.src.join(path).join("Cargo.lock"); - let mut contents = String::new(); - t!(t!(File::open(&lockfile)).read_to_string(&mut contents)); - let mut lines = contents.lines(); - while let Some(line) = lines.next() { - let prefix = "name = \""; - if !line.starts_with(prefix) { - continue + match krate { + Some(krate) => { + cargo.arg("-p").arg(krate); } - lines.next(); // skip `version = ...` - - // skip crates.io or otherwise non-path crates - if let Some(line) = lines.next() { - if line.starts_with("source") { - continue + None => { + let mut visited = HashSet::new(); + let mut next = vec![root]; + while let Some(name) = next.pop() { + // Right now jemalloc is our only target-specific crate in the sense + // that it's not present on all platforms. Custom skip it here for now, + // but if we add more this probably wants to get more generalized. + if !name.contains("jemalloc") { + cargo.arg("-p").arg(name); + } + for dep in build.crates[name].deps.iter() { + if visited.insert(dep) { + next.push(dep); + } + } } } - - let crate_name = &line[prefix.len()..line.len() - 1]; - - // Right now jemalloc is our only target-specific crate in the sense - // that it's not present on all platforms. Custom skip it here for now, - // but if we add more this probably wants to get more generalized. - if crate_name.contains("jemalloc") { - continue - } - - cargo.arg("-p").arg(crate_name); } // The tests are going to run with the *target* libraries, so we need to @@ -320,11 +336,19 @@ pub fn krate(build: &Build, dylib_path.insert(0, build.sysroot_libdir(compiler, target)); cargo.env(dylib_path_var(), env::join_paths(&dylib_path).unwrap()); + if build.config.quiet_tests { + cargo.arg("--"); + cargo.arg("--quiet"); + } + if target.contains("android") { build.run(cargo.arg("--no-run")); krate_android(build, compiler, target, mode); + } else if target.contains("emscripten") { + build.run(cargo.arg("--no-run")); + krate_emscripten(build, compiler, target, mode); } else { - cargo.args(&build.flags.args); + cargo.args(&build.flags.cmd.test_args()); build.run(&mut cargo); } } @@ -356,7 +380,7 @@ fn krate_android(build: &Build, target = target, test = test_file_name, log = log, - args = build.flags.args.join(" ")); + args = build.flags.cmd.test_args().join(" ")); let output = output(Command::new("adb").arg("shell").arg(&program)); println!("{}", output); @@ -371,6 +395,35 @@ fn krate_android(build: &Build, } } +fn krate_emscripten(build: &Build, + compiler: &Compiler, + target: &str, + mode: Mode) { + let mut tests = Vec::new(); + let out_dir = build.cargo_out(compiler, mode, target); + find_tests(&out_dir, target, &mut tests); + find_tests(&out_dir.join("deps"), target, &mut tests); + + for test in tests { + let test_file_name = test.to_string_lossy().into_owned(); + println!("running {}", test_file_name); + let nodejs = build.config.nodejs.as_ref().expect("nodejs not configured"); + let status = Command::new(nodejs) + .arg(&test_file_name) + .stderr(::std::process::Stdio::inherit()) + .status(); + match status { + Ok(status) => { + if !status.success() { + panic!("some tests failed"); + } + } + Err(e) => panic!(format!("failed to execute command: {}", e)), + }; + } + } + + fn find_tests(dir: &Path, target: &str, dst: &mut Vec) { @@ -381,7 +434,8 @@ fn find_tests(dir: &Path, } let filename = e.file_name().into_string().unwrap(); if (target.contains("windows") && filename.ends_with(".exe")) || - (!target.contains("windows") && !filename.contains(".")) { + (!target.contains("windows") && !filename.contains(".")) || + (target.contains("emscripten") && filename.contains(".js")){ dst.push(e.path()); } } diff --git a/src/bootstrap/clean.rs b/src/bootstrap/clean.rs index a1e286e162..75bcbfee6e 100644 --- a/src/bootstrap/clean.rs +++ b/src/bootstrap/clean.rs @@ -16,6 +16,7 @@ //! directory as we want that cached between builds. use std::fs; +use std::io::{self, ErrorKind}; use std::path::Path; use Build; @@ -25,24 +26,58 @@ pub fn clean(build: &Build) { rm_rf(build, &build.out.join("tmp")); for host in build.config.host.iter() { + let entries = match build.out.join(host).read_dir() { + Ok(iter) => iter, + Err(_) => continue, + }; - let out = build.out.join(host); + for entry in entries { + let entry = t!(entry); + if entry.file_name().to_str() == Some("llvm") { + continue + } + let path = t!(entry.path().canonicalize()); + rm_rf(build, &path); + } + } +} - rm_rf(build, &out.join("doc")); +fn rm_rf(build: &Build, path: &Path) { + if !path.exists() { + return + } - for stage in 0..4 { - rm_rf(build, &out.join(format!("stage{}", stage))); - rm_rf(build, &out.join(format!("stage{}-std", stage))); - rm_rf(build, &out.join(format!("stage{}-rustc", stage))); - rm_rf(build, &out.join(format!("stage{}-tools", stage))); - rm_rf(build, &out.join(format!("stage{}-test", stage))); + for file in t!(fs::read_dir(path)) { + let file = t!(file).path(); + + if file.is_dir() { + rm_rf(build, &file); + } else { + // On windows we can't remove a readonly file, and git will + // often clone files as readonly. As a result, we have some + // special logic to remove readonly files on windows. + do_op(&file, "remove file", |p| fs::remove_file(p)); } } + do_op(path, "remove dir", |p| fs::remove_dir(p)); } -fn rm_rf(build: &Build, path: &Path) { - if path.exists() { - build.verbose(&format!("removing `{}`", path.display())); - t!(fs::remove_dir_all(path)); +fn do_op(path: &Path, desc: &str, mut f: F) + where F: FnMut(&Path) -> io::Result<()> +{ + match f(path) { + Ok(()) => {} + Err(ref e) if cfg!(windows) && + e.kind() == ErrorKind::PermissionDenied => { + let mut p = t!(path.metadata()).permissions(); + p.set_readonly(false); + t!(fs::set_permissions(path, p)); + f(path).unwrap_or_else(|e| { + panic!("failed to {} {}: {}", desc, path.display(), e); + }) + } + Err(e) => { + panic!("failed to {} {}: {}", desc, path.display(), e); + } } } diff --git a/src/bootstrap/compile.rs b/src/bootstrap/compile.rs index 239db55ff5..5fc4f00672 100644 --- a/src/bootstrap/compile.rs +++ b/src/bootstrap/compile.rs @@ -25,7 +25,7 @@ use std::process::Command; use build_helper::output; use filetime::FileTime; -use util::{exe, staticlib, libdir, mtime, is_dylib, copy}; +use util::{exe, libdir, mtime, is_dylib, copy}; use {Build, Compiler, Mode}; /// Build the standard library. @@ -40,20 +40,6 @@ pub fn std<'a>(build: &'a Build, target: &str, compiler: &Compiler<'a>) { let libdir = build.sysroot_libdir(compiler, target); let _ = fs::remove_dir_all(&libdir); t!(fs::create_dir_all(&libdir)); - // FIXME(stage0) remove this `if` after the next snapshot - // The stage0 compiler still passes the `-lcompiler-rt` flag to the linker but now `bootstrap` - // never builds a `libcopmiler-rt.a`! We'll fill the hole by simply copying stage0's - // `libcompiler-rt.a` to where the stage1's one is expected (though we could as well just use - // an empty `.a` archive). Note that the symbols of that stage0 `libcompiler-rt.a` won't make - // it to the final binary because now `libcore.rlib` also contains the symbols that - // `libcompiler-rt.a` provides. Since that rlib appears first in the linker arguments, its - // symbols are used instead of `libcompiler-rt.a`'s. - if compiler.stage == 0 { - let rtlib = &staticlib("compiler-rt", target); - let src = build.rustc.parent().unwrap().parent().unwrap().join("lib").join("rustlib") - .join(target).join("lib").join(rtlib); - copy(&src, &libdir.join(rtlib)); - } // Some platforms have startup objects that may be required to produce the // libstd dynamic library, for example. @@ -78,8 +64,8 @@ pub fn std<'a>(build: &'a Build, target: &str, compiler: &Compiler<'a>) { } build.run(&mut cargo); - update_mtime(&libstd_stamp(build, compiler, target)); - std_link(build, target, compiler, compiler.host); + update_mtime(&libstd_stamp(build, &compiler, target)); + std_link(build, target, compiler.stage, compiler.host); } /// Link all libstd rlibs/dylibs into the sysroot location. @@ -88,11 +74,12 @@ pub fn std<'a>(build: &'a Build, target: &str, compiler: &Compiler<'a>) { /// by `compiler` into `host`'s sysroot. pub fn std_link(build: &Build, target: &str, - compiler: &Compiler, + stage: u32, host: &str) { + let compiler = Compiler::new(stage, &build.config.build); let target_compiler = Compiler::new(compiler.stage, host); let libdir = build.sysroot_libdir(&target_compiler, target); - let out_dir = build.cargo_out(compiler, Mode::Libstd, target); + let out_dir = build.cargo_out(&compiler, Mode::Libstd, target); // If we're linking one compiler host's output into another, then we weren't // called from the `std` method above. In that case we clean out what's @@ -104,16 +91,16 @@ pub fn std_link(build: &Build, add_to_sysroot(&out_dir, &libdir); if target.contains("musl") && !target.contains("mips") { - copy_musl_third_party_objects(build, &libdir); + copy_musl_third_party_objects(build, target, &libdir); } } /// Copies the crt(1,i,n).o startup objects /// /// Only required for musl targets that statically link to libc -fn copy_musl_third_party_objects(build: &Build, into: &Path) { +fn copy_musl_third_party_objects(build: &Build, target: &str, into: &Path) { for &obj in &["crt1.o", "crti.o", "crtn.o"] { - copy(&build.config.musl_root.as_ref().unwrap().join("lib").join(obj), &into.join(obj)); + copy(&build.musl_root(target).unwrap().join("lib").join(obj), &into.join(obj)); } } @@ -160,7 +147,7 @@ pub fn test<'a>(build: &'a Build, target: &str, compiler: &Compiler<'a>) { .arg(build.src.join("src/rustc/test_shim/Cargo.toml")); build.run(&mut cargo); update_mtime(&libtest_stamp(build, compiler, target)); - test_link(build, target, compiler, compiler.host); + test_link(build, target, compiler.stage, compiler.host); } /// Link all libtest rlibs/dylibs into the sysroot location. @@ -169,11 +156,12 @@ pub fn test<'a>(build: &'a Build, target: &str, compiler: &Compiler<'a>) { /// by `compiler` into `host`'s sysroot. pub fn test_link(build: &Build, target: &str, - compiler: &Compiler, + stage: u32, host: &str) { + let compiler = Compiler::new(stage, &build.config.build); let target_compiler = Compiler::new(compiler.stage, host); let libdir = build.sysroot_libdir(&target_compiler, target); - let out_dir = build.cargo_out(compiler, Mode::Libtest, target); + let out_dir = build.cargo_out(&compiler, Mode::Libtest, target); add_to_sysroot(&out_dir, &libdir); } @@ -232,7 +220,7 @@ pub fn rustc<'a>(build: &'a Build, target: &str, compiler: &Compiler<'a>) { } build.run(&mut cargo); - rustc_link(build, target, compiler, compiler.host); + rustc_link(build, target, compiler.stage, compiler.host); } /// Link all librustc rlibs/dylibs into the sysroot location. @@ -241,11 +229,12 @@ pub fn rustc<'a>(build: &'a Build, target: &str, compiler: &Compiler<'a>) { /// by `compiler` into `host`'s sysroot. pub fn rustc_link(build: &Build, target: &str, - compiler: &Compiler, + stage: u32, host: &str) { + let compiler = Compiler::new(stage, &build.config.build); let target_compiler = Compiler::new(compiler.stage, host); let libdir = build.sysroot_libdir(&target_compiler, target); - let out_dir = build.cargo_out(compiler, Mode::Librustc, target); + let out_dir = build.cargo_out(&compiler, Mode::Librustc, target); add_to_sysroot(&out_dir, &libdir); } @@ -273,7 +262,10 @@ fn compiler_file(compiler: &Path, file: &str) -> PathBuf { /// must have been previously produced by the `stage - 1` build.config.build /// compiler. pub fn assemble_rustc(build: &Build, stage: u32, host: &str) { - assert!(stage > 0, "the stage0 compiler isn't assembled, it's downloaded"); + // nothing to do in stage0 + if stage == 0 { + return + } // The compiler that we're assembling let target_compiler = Compiler::new(stage, host); diff --git a/src/bootstrap/config.rs b/src/bootstrap/config.rs index 0f69bcfbb6..bb05b75a3f 100644 --- a/src/bootstrap/config.rs +++ b/src/bootstrap/config.rs @@ -23,6 +23,7 @@ use std::process; use num_cpus; use rustc_serialize::Decodable; use toml::{Parser, Decoder, Value}; +use util::push_exe_path; /// Global configuration for the entire build and/or bootstrap. /// @@ -56,6 +57,7 @@ pub struct Config { pub rust_codegen_units: u32, pub rust_debug_assertions: bool, pub rust_debuginfo: bool, + pub rust_debuginfo_lines: bool, pub rust_rpath: bool, pub rustc_default_linker: Option, pub rustc_default_ar: Option, @@ -76,11 +78,16 @@ pub struct Config { // misc pub channel: String, + pub quiet_tests: bool, // Fallback musl-root for all targets pub musl_root: Option, pub prefix: Option, + pub docdir: Option, + pub libdir: Option, + pub mandir: Option, pub codegen_tests: bool, pub nodejs: Option, + pub gdb: Option, } /// Per-target configuration stored in the global configuration structure. @@ -117,6 +124,8 @@ struct Build { rustc: Option, compiler_docs: Option, docs: Option, + submodules: Option, + gdb: Option, } /// TOML representation of how the LLVM build is configured. @@ -137,6 +146,7 @@ struct Rust { codegen_units: Option, debug_assertions: Option, debuginfo: Option, + debuginfo_lines: Option, debug_jemalloc: Option, use_jemalloc: Option, backtrace: Option, @@ -158,6 +168,7 @@ struct TomlTarget { cc: Option, cxx: Option, android_ndk: Option, + musl_root: Option, } impl Config { @@ -219,8 +230,10 @@ impl Config { } config.rustc = build.rustc.map(PathBuf::from); config.cargo = build.cargo.map(PathBuf::from); + config.gdb = build.gdb.map(PathBuf::from); set(&mut config.compiler_docs, build.compiler_docs); set(&mut config.docs, build.docs); + set(&mut config.submodules, build.submodules); if let Some(ref llvm) = toml.llvm { set(&mut config.ccache, llvm.ccache); @@ -233,6 +246,7 @@ impl Config { if let Some(ref rust) = toml.rust { set(&mut config.rust_debug_assertions, rust.debug_assertions); set(&mut config.rust_debuginfo, rust.debuginfo); + set(&mut config.rust_debuginfo_lines, rust.debuginfo_lines); set(&mut config.rust_optimize, rust.optimize); set(&mut config.rust_optimize_tests, rust.optimize_tests); set(&mut config.rust_debuginfo_tests, rust.debuginfo_tests); @@ -268,6 +282,7 @@ impl Config { } target.cxx = cfg.cxx.clone().map(PathBuf::from); target.cc = cfg.cc.clone().map(PathBuf::from); + target.musl_root = cfg.musl_root.clone().map(PathBuf::from); config.target_config.insert(triple.clone(), target); } @@ -322,11 +337,13 @@ impl Config { ("OPTIMIZE", self.rust_optimize), ("DEBUG_ASSERTIONS", self.rust_debug_assertions), ("DEBUGINFO", self.rust_debuginfo), + ("DEBUGINFO_LINES", self.rust_debuginfo_lines), ("JEMALLOC", self.use_jemalloc), ("DEBUG_JEMALLOC", self.debug_jemalloc), ("RPATH", self.rust_rpath), ("OPTIMIZE_TESTS", self.rust_optimize_tests), ("DEBUGINFO_TESTS", self.rust_debuginfo_tests), + ("QUIET_TESTS", self.quiet_tests), ("LOCAL_REBUILD", self.local_rebuild), ("NINJA", self.ninja), ("CODEGEN_TESTS", self.codegen_tests), @@ -343,7 +360,37 @@ impl Config { .collect(); } "CFG_MUSL_ROOT" if value.len() > 0 => { - self.musl_root = Some(PathBuf::from(value)); + self.musl_root = Some(parse_configure_path(value)); + } + "CFG_MUSL_ROOT_X86_64" if value.len() > 0 => { + let target = "x86_64-unknown-linux-musl".to_string(); + let target = self.target_config.entry(target) + .or_insert(Target::default()); + target.musl_root = Some(parse_configure_path(value)); + } + "CFG_MUSL_ROOT_I686" if value.len() > 0 => { + let target = "i686-unknown-linux-musl".to_string(); + let target = self.target_config.entry(target) + .or_insert(Target::default()); + target.musl_root = Some(parse_configure_path(value)); + } + "CFG_MUSL_ROOT_ARM" if value.len() > 0 => { + let target = "arm-unknown-linux-musleabi".to_string(); + let target = self.target_config.entry(target) + .or_insert(Target::default()); + target.musl_root = Some(parse_configure_path(value)); + } + "CFG_MUSL_ROOT_ARMHF" if value.len() > 0 => { + let target = "arm-unknown-linux-musleabihf".to_string(); + let target = self.target_config.entry(target) + .or_insert(Target::default()); + target.musl_root = Some(parse_configure_path(value)); + } + "CFG_MUSL_ROOT_ARMV7" if value.len() > 0 => { + let target = "armv7-unknown-linux-musleabihf".to_string(); + let target = self.target_config.entry(target) + .or_insert(Target::default()); + target.musl_root = Some(parse_configure_path(value)); } "CFG_DEFAULT_AR" if value.len() > 0 => { self.rustc_default_ar = Some(value.to_string()); @@ -351,53 +398,63 @@ impl Config { "CFG_DEFAULT_LINKER" if value.len() > 0 => { self.rustc_default_linker = Some(value.to_string()); } + "CFG_GDB" if value.len() > 0 => { + self.gdb = Some(parse_configure_path(value)); + } "CFG_RELEASE_CHANNEL" => { self.channel = value.to_string(); } "CFG_PREFIX" => { self.prefix = Some(value.to_string()); } + "CFG_DOCDIR" => { + self.docdir = Some(value.to_string()); + } + "CFG_LIBDIR" => { + self.libdir = Some(value.to_string()); + } + "CFG_MANDIR" => { + self.mandir = Some(value.to_string()); + } "CFG_LLVM_ROOT" if value.len() > 0 => { let target = self.target_config.entry(self.build.clone()) .or_insert(Target::default()); - let root = PathBuf::from(value); - target.llvm_config = Some(root.join("bin/llvm-config")); + let root = parse_configure_path(value); + target.llvm_config = Some(push_exe_path(root, &["bin", "llvm-config"])); } "CFG_JEMALLOC_ROOT" if value.len() > 0 => { let target = self.target_config.entry(self.build.clone()) .or_insert(Target::default()); - target.jemalloc = Some(PathBuf::from(value)); + target.jemalloc = Some(parse_configure_path(value)); } "CFG_ARM_LINUX_ANDROIDEABI_NDK" if value.len() > 0 => { let target = "arm-linux-androideabi".to_string(); let target = self.target_config.entry(target) .or_insert(Target::default()); - target.ndk = Some(PathBuf::from(value)); + target.ndk = Some(parse_configure_path(value)); } "CFG_ARMV7_LINUX_ANDROIDEABI_NDK" if value.len() > 0 => { let target = "armv7-linux-androideabi".to_string(); let target = self.target_config.entry(target) .or_insert(Target::default()); - target.ndk = Some(PathBuf::from(value)); + target.ndk = Some(parse_configure_path(value)); } "CFG_I686_LINUX_ANDROID_NDK" if value.len() > 0 => { let target = "i686-linux-android".to_string(); let target = self.target_config.entry(target) .or_insert(Target::default()); - target.ndk = Some(PathBuf::from(value)); + target.ndk = Some(parse_configure_path(value)); } "CFG_AARCH64_LINUX_ANDROID_NDK" if value.len() > 0 => { let target = "aarch64-linux-android".to_string(); let target = self.target_config.entry(target) .or_insert(Target::default()); - target.ndk = Some(PathBuf::from(value)); + target.ndk = Some(parse_configure_path(value)); } "CFG_LOCAL_RUST_ROOT" if value.len() > 0 => { - self.rustc = Some(PathBuf::from(value).join("bin/rustc")); - self.cargo = Some(PathBuf::from(value).join("bin/cargo")); - } - "CFG_NODEJS" if value.len() > 0 => { - self.nodejs = Some(PathBuf::from(value)); + let path = parse_configure_path(value); + self.rustc = Some(push_exe_path(path.clone(), &["bin", "rustc"])); + self.cargo = Some(push_exe_path(path, &["bin", "cargo"])); } _ => {} } @@ -405,6 +462,30 @@ impl Config { } } +#[cfg(not(windows))] +fn parse_configure_path(path: &str) -> PathBuf { + path.into() +} + +#[cfg(windows)] +fn parse_configure_path(path: &str) -> PathBuf { + // on windows, configure produces unix style paths e.g. /c/some/path but we + // only want real windows paths + + use std::process::Command; + use build_helper; + + // '/' is invalid in windows paths, so we can detect unix paths by the presence of it + if !path.contains('/') { + return path.into(); + } + + let win_path = build_helper::output(Command::new("cygpath").arg("-w").arg(path)); + let win_path = win_path.trim(); + + win_path.into() +} + fn set(field: &mut T, val: Option) { if let Some(v) = val { *field = v; diff --git a/src/bootstrap/config.toml.example b/src/bootstrap/config.toml.example index f054b29d0b..1289cdba59 100644 --- a/src/bootstrap/config.toml.example +++ b/src/bootstrap/config.toml.example @@ -76,6 +76,12 @@ # library and facade crates. #compiler-docs = false +# Indicate whether submodules are managed and updated automatically. +#submodules = true + +# The path to (or name of) the GDB executable to use +#gdb = "gdb" + # ============================================================================= # Options for compiling Rust code itself # ============================================================================= @@ -96,6 +102,9 @@ # Whether or not debuginfo is emitted #debuginfo = false +# Whether or not line number debug information is emitted +#debuginfo-lines = false + # Whether or not jemalloc is built and enabled #use-jemalloc = true diff --git a/src/bootstrap/dist.rs b/src/bootstrap/dist.rs index 31b7db168b..8676f5cc4a 100644 --- a/src/bootstrap/dist.rs +++ b/src/bootstrap/dist.rs @@ -25,9 +25,8 @@ use std::process::Command; use {Build, Compiler}; use util::{cp_r, libdir, is_dylib, cp_filtered, copy}; -use regex::{RegexSet, quote}; -fn package_vers(build: &Build) -> &str { +pub fn package_vers(build: &Build) -> &str { match &build.config.channel[..] { "stable" => &build.release, "beta" => "beta", @@ -40,7 +39,7 @@ fn distdir(build: &Build) -> PathBuf { build.out.join("dist") } -fn tmpdir(build: &Build) -> PathBuf { +pub fn tmpdir(build: &Build) -> PathBuf { build.out.join("tmp/dist") } @@ -315,49 +314,31 @@ pub fn rust_src(build: &Build) { "mk" ]; - // Exclude paths matching these wildcard expressions - let excludes = [ - // exclude-vcs - "CVS", "RCS", "SCCS", ".git", ".gitignore", ".gitmodules", ".gitattributes", ".cvsignore", - ".svn", ".arch-ids", "{arch}", "=RELEASE-ID", "=meta-update", "=update", ".bzr", - ".bzrignore", ".bzrtags", ".hg", ".hgignore", ".hgrags", "_darcs", - // extensions - "*~", "*.pyc", - // misc - "llvm/test/*/*.ll", - "llvm/test/*/*.td", - "llvm/test/*/*.s", - "llvm/test/*/*/*.ll", - "llvm/test/*/*/*.td", - "llvm/test/*/*/*.s" - ]; - - // Construct a set of regexes for efficiently testing whether paths match one of the above - // expressions. - let regex_set = t!(RegexSet::new( - // This converts a wildcard expression to a regex - excludes.iter().map(|&s| { - // Prefix ensures that matching starts on a path separator boundary - r"^(.*[\\/])?".to_owned() + ( - // Escape the expression to produce a regex matching exactly that string - "e(s) - // Replace slashes with a pattern matching either forward or backslash - .replace(r"/", r"[\\/]") - // Replace wildcards with a pattern matching a single path segment, ie. containing - // no slashes. - .replace(r"\*", r"[^\\/]*") - // Suffix anchors to the end of the path - ) + "$" - }) - )); - - // Create a filter which skips files which match the regex set or contain invalid unicode let filter_fn = move |path: &Path| { - if let Some(path) = path.to_str() { - !regex_set.is_match(path) - } else { - false + let spath = match path.to_str() { + Some(path) => path, + None => return false, + }; + if spath.ends_with("~") || spath.ends_with(".pyc") { + return false } + if spath.contains("llvm/test") || spath.contains("llvm\\test") { + if spath.ends_with(".ll") || + spath.ends_with(".td") || + spath.ends_with(".s") { + return false + } + } + + let excludes = [ + "CVS", "RCS", "SCCS", ".git", ".gitignore", ".gitmodules", + ".gitattributes", ".cvsignore", ".svn", ".arch-ids", "{arch}", + "=RELEASE-ID", "=meta-update", "=update", ".bzr", ".bzrignore", + ".bzrtags", ".hg", ".hgignore", ".hgrags", "_darcs", + ]; + !path.iter() + .map(|s| s.to_str().unwrap()) + .any(|s| excludes.contains(&s)) }; // Copy the directories using our filter @@ -418,7 +399,7 @@ fn chmod(_path: &Path, _perms: u32) {} // We have to run a few shell scripts, which choke quite a bit on both `\` // characters and on `C:\` paths, so normalize both of them away. -fn sanitize_sh(path: &Path) -> String { +pub fn sanitize_sh(path: &Path) -> String { let path = path.to_str().unwrap().replace("\\", "/"); return change_drive(&path).unwrap_or(path); diff --git a/src/bootstrap/doc.rs b/src/bootstrap/doc.rs index c2636384db..30c7fefad8 100644 --- a/src/bootstrap/doc.rs +++ b/src/bootstrap/doc.rs @@ -19,7 +19,6 @@ use std::fs::{self, File}; use std::io::prelude::*; -use std::path::Path; use std::process::Command; use {Build, Compiler, Mode}; @@ -30,8 +29,9 @@ use util::{up_to_date, cp_r}; /// /// This will not actually generate any documentation if the documentation has /// already been generated. -pub fn rustbook(build: &Build, stage: u32, target: &str, name: &str, out: &Path) { - t!(fs::create_dir_all(out)); +pub fn rustbook(build: &Build, stage: u32, target: &str, name: &str) { + let out = build.doc_out(target); + t!(fs::create_dir_all(&out)); let out = out.join(name); let compiler = Compiler::new(stage, &build.config.build); @@ -57,9 +57,10 @@ pub fn rustbook(build: &Build, stage: u32, target: &str, name: &str, out: &Path) /// `STAMP` alongw ith providing the various header/footer HTML we've cutomized. /// /// In the end, this is just a glorified wrapper around rustdoc! -pub fn standalone(build: &Build, stage: u32, target: &str, out: &Path) { +pub fn standalone(build: &Build, stage: u32, target: &str) { println!("Documenting stage{} standalone ({})", stage, target); - t!(fs::create_dir_all(out)); + let out = build.doc_out(target); + t!(fs::create_dir_all(&out)); let compiler = Compiler::new(stage, &build.config.build); @@ -109,7 +110,7 @@ pub fn standalone(build: &Build, stage: u32, target: &str, out: &Path) { .arg("--html-in-header").arg(&favicon) .arg("--markdown-playground-url") .arg("https://play.rust-lang.org/") - .arg("-o").arg(out) + .arg("-o").arg(&out) .arg(&path); if filename == "reference.md" { @@ -131,9 +132,10 @@ pub fn standalone(build: &Build, stage: u32, target: &str, out: &Path) { /// /// This will generate all documentation for the standard library and its /// dependencies. This is largely just a wrapper around `cargo doc`. -pub fn std(build: &Build, stage: u32, target: &str, out: &Path) { +pub fn std(build: &Build, stage: u32, target: &str) { println!("Documenting stage{} std ({})", stage, target); - t!(fs::create_dir_all(out)); + let out = build.doc_out(target); + t!(fs::create_dir_all(&out)); let compiler = Compiler::new(stage, &build.config.build); let out_dir = build.stage_out(&compiler, Mode::Libstd) .join(target).join("doc"); @@ -146,16 +148,17 @@ pub fn std(build: &Build, stage: u32, target: &str, out: &Path) { .arg(build.src.join("src/rustc/std_shim/Cargo.toml")) .arg("--features").arg(build.std_features()); build.run(&mut cargo); - cp_r(&out_dir, out) + cp_r(&out_dir, &out) } /// Compile all libtest documentation. /// /// This will generate all documentation for libtest and its dependencies. This /// is largely just a wrapper around `cargo doc`. -pub fn test(build: &Build, stage: u32, target: &str, out: &Path) { +pub fn test(build: &Build, stage: u32, target: &str) { println!("Documenting stage{} test ({})", stage, target); - t!(fs::create_dir_all(out)); + let out = build.doc_out(target); + t!(fs::create_dir_all(&out)); let compiler = Compiler::new(stage, &build.config.build); let out_dir = build.stage_out(&compiler, Mode::Libtest) .join(target).join("doc"); @@ -167,16 +170,17 @@ pub fn test(build: &Build, stage: u32, target: &str, out: &Path) { cargo.arg("--manifest-path") .arg(build.src.join("src/rustc/test_shim/Cargo.toml")); build.run(&mut cargo); - cp_r(&out_dir, out) + cp_r(&out_dir, &out) } /// Generate all compiler documentation. /// /// This will generate all documentation for the compiler libraries and their /// dependencies. This is largely just a wrapper around `cargo doc`. -pub fn rustc(build: &Build, stage: u32, target: &str, out: &Path) { +pub fn rustc(build: &Build, stage: u32, target: &str) { println!("Documenting stage{} compiler ({})", stage, target); - t!(fs::create_dir_all(out)); + let out = build.doc_out(target); + t!(fs::create_dir_all(&out)); let compiler = Compiler::new(stage, &build.config.build); let out_dir = build.stage_out(&compiler, Mode::Librustc) .join(target).join("doc"); @@ -189,14 +193,15 @@ pub fn rustc(build: &Build, stage: u32, target: &str, out: &Path) { .arg(build.src.join("src/rustc/Cargo.toml")) .arg("--features").arg(build.rustc_features()); build.run(&mut cargo); - cp_r(&out_dir, out) + cp_r(&out_dir, &out) } /// Generates the HTML rendered error-index by running the /// `error_index_generator` tool. -pub fn error_index(build: &Build, stage: u32, target: &str, out: &Path) { +pub fn error_index(build: &Build, stage: u32, target: &str) { println!("Documenting stage{} error index ({})", stage, target); - t!(fs::create_dir_all(out)); + let out = build.doc_out(target); + t!(fs::create_dir_all(&out)); let compiler = Compiler::new(stage, &build.config.build); let mut index = build.tool_cmd(&compiler, "error_index_generator"); index.arg("html"); diff --git a/src/bootstrap/flags.rs b/src/bootstrap/flags.rs index d925997f36..d7516954f1 100644 --- a/src/bootstrap/flags.rs +++ b/src/bootstrap/flags.rs @@ -13,30 +13,46 @@ //! This module implements the command-line parsing of the build system which //! has various flags to configure how it's run. +use std::env; use std::fs; use std::path::PathBuf; use std::process; -use std::slice; -use getopts::Options; +use getopts::{Matches, Options}; + +use Build; +use config::Config; +use metadata; +use step; /// Deserialized version of all flags for this compile. pub struct Flags { pub verbose: bool, pub stage: Option, pub build: String, - pub host: Filter, - pub target: Filter, - pub step: Vec, + pub host: Vec, + pub target: Vec, pub config: Option, pub src: Option, pub jobs: Option, - pub args: Vec, - pub clean: bool, + pub cmd: Subcommand, } -pub struct Filter { - values: Vec, +pub enum Subcommand { + Build { + paths: Vec, + }, + Doc { + paths: Vec, + }, + Test { + paths: Vec, + test_args: Vec, + }, + Clean, + Dist { + install: bool, + }, } impl Flags { @@ -44,29 +60,177 @@ impl Flags { let mut opts = Options::new(); opts.optflag("v", "verbose", "use verbose output"); opts.optopt("", "config", "TOML configuration file for build", "FILE"); + opts.optopt("", "build", "build target of the stage0 compiler", "BUILD"); opts.optmulti("", "host", "host targets to build", "HOST"); - opts.reqopt("", "build", "build target of the stage0 compiler", "BUILD"); - opts.optmulti("", "target", "targets to build", "TARGET"); - opts.optmulti("s", "step", "build step to execute", "STEP"); + opts.optmulti("", "target", "target targets to build", "TARGET"); opts.optopt("", "stage", "stage to build", "N"); - opts.optopt("", "src", "path to repo root", "DIR"); + opts.optopt("", "src", "path to the root of the rust checkout", "DIR"); opts.optopt("j", "jobs", "number of jobs to run in parallel", "JOBS"); - opts.optflag("", "clean", "clean output directory"); opts.optflag("h", "help", "print this help message"); - let usage = |n| -> ! { - let brief = format!("Usage: rust.py [options]"); - print!("{}", opts.usage(&brief)); + let usage = |n, opts: &Options| -> ! { + let command = args.get(0).map(|s| &**s); + let brief = format!("Usage: x.py {} [options] [...]", + command.unwrap_or("")); + + println!("{}", opts.usage(&brief)); + match command { + Some("build") => { + println!("\ +Arguments: + This subcommand accepts a number of positional arguments of directories to + the crates and/or artifacts to compile. For example: + + ./x.py build src/libcore + ./x.py build src/libproc_macro + ./x.py build src/libstd --stage 1 + + If no arguments are passed then the complete artifacts for that stage are + also compiled. + + ./x.py build + ./x.py build --stage 1 + + For a quick build with a usable compile, you can pass: + + ./x.py build --stage 1 src/libtest +"); + } + + Some("test") => { + println!("\ +Arguments: + This subcommand accepts a number of positional arguments of directories to + tests that should be compiled and run. For example: + + ./x.py test src/test/run-pass + ./x.py test src/test/run-pass/assert-* + ./x.py test src/libstd --test-args hash_map + ./x.py test src/libstd --stage 0 + + If no arguments are passed then the complete artifacts for that stage are + compiled and tested. + + ./x.py test + ./x.py test --stage 1 +"); + } + + Some("doc") => { + println!("\ +Arguments: + This subcommand accepts a number of positional arguments of directories of + documentation to build. For example: + + ./x.py doc src/doc/book + ./x.py doc src/doc/nomicon + ./x.py doc src/libstd + + If no arguments are passed then everything is documented: + + ./x.py doc + ./x.py doc --stage 1 +"); + } + + _ => {} + } + + if let Some(command) = command { + if command == "build" || + command == "dist" || + command == "doc" || + command == "test" || + command == "clean" { + println!("Available invocations:"); + if args.iter().any(|a| a == "-v") { + let flags = Flags::parse(&["build".to_string()]); + let mut config = Config::default(); + config.build = flags.build.clone(); + let mut build = Build::new(flags, config); + metadata::build(&mut build); + step::build_rules(&build).print_help(command); + } else { + println!(" ... elided, run `./x.py {} -h -v` to see", + command); + } + + println!(""); + } + } + +println!("\ +Subcommands: + build Compile either the compiler or libraries + test Build and run some test suites + doc Build documentation + clean Clean out build directories + dist Build and/or install distribution artifacts + +To learn more about a subcommand, run `./x.py -h` +"); + process::exit(n); }; - - let m = opts.parse(args).unwrap_or_else(|e| { - println!("failed to parse options: {}", e); - usage(1); - }); - if m.opt_present("h") { - usage(0); + if args.len() == 0 { + println!("a command must be passed"); + usage(1, &opts); } + let parse = |opts: &Options| { + let m = opts.parse(&args[1..]).unwrap_or_else(|e| { + println!("failed to parse options: {}", e); + usage(1, opts); + }); + if m.opt_present("h") { + usage(0, opts); + } + return m + }; + + let cwd = t!(env::current_dir()); + let remaining_as_path = |m: &Matches| { + m.free.iter().map(|p| cwd.join(p)).collect::>() + }; + + let m: Matches; + let cmd = match &args[0][..] { + "build" => { + m = parse(&opts); + Subcommand::Build { paths: remaining_as_path(&m) } + } + "doc" => { + m = parse(&opts); + Subcommand::Doc { paths: remaining_as_path(&m) } + } + "test" => { + opts.optmulti("", "test-args", "extra arguments", "ARGS"); + m = parse(&opts); + Subcommand::Test { + paths: remaining_as_path(&m), + test_args: m.opt_strs("test-args"), + } + } + "clean" => { + m = parse(&opts); + if m.free.len() > 0 { + println!("clean takes no arguments"); + usage(1, &opts); + } + Subcommand::Clean + } + "dist" => { + opts.optflag("", "install", "run installer as well"); + m = parse(&opts); + Subcommand::Dist { + install: m.opt_present("install"), + } + } + cmd => { + println!("unknown command: {}", cmd); + usage(1, &opts); + } + }; + let cfg_file = m.opt_str("config").map(PathBuf::from).or_else(|| { if fs::metadata("config.toml").is_ok() { @@ -78,26 +242,27 @@ impl Flags { Flags { verbose: m.opt_present("v"), - clean: m.opt_present("clean"), stage: m.opt_str("stage").map(|j| j.parse().unwrap()), - build: m.opt_str("build").unwrap(), - host: Filter { values: m.opt_strs("host") }, - target: Filter { values: m.opt_strs("target") }, - step: m.opt_strs("step"), + build: m.opt_str("build").unwrap_or_else(|| { + env::var("BUILD").unwrap() + }), + host: m.opt_strs("host"), + target: m.opt_strs("target"), config: cfg_file, src: m.opt_str("src").map(PathBuf::from), jobs: m.opt_str("jobs").map(|j| j.parse().unwrap()), - args: m.free.clone(), + cmd: cmd, } } } -impl Filter { - pub fn contains(&self, name: &str) -> bool { - self.values.len() == 0 || self.values.iter().any(|s| s == name) - } - - pub fn iter(&self) -> slice::Iter { - self.values.iter() +impl Subcommand { + pub fn test_args(&self) -> Vec<&str> { + match *self { + Subcommand::Test { ref test_args, .. } => { + test_args.iter().flat_map(|s| s.split_whitespace()).collect() + } + _ => Vec::new(), + } } } diff --git a/src/bootstrap/install.rs b/src/bootstrap/install.rs new file mode 100644 index 0000000000..9bc5a7c00a --- /dev/null +++ b/src/bootstrap/install.rs @@ -0,0 +1,61 @@ +// Copyright 2016 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +//! Implementation of the install aspects of the compiler. +//! +//! This module is responsible for installing the standard library, +//! compiler, and documentation. + +use std::fs; +use std::borrow::Cow; +use std::path::Path; +use std::process::Command; + +use Build; +use dist::{package_vers, sanitize_sh, tmpdir}; + +/// Installs everything. +pub fn install(build: &Build, stage: u32, host: &str) { + let prefix = build.config.prefix.as_ref().clone().map(|x| Path::new(x)) + .unwrap_or(Path::new("/usr/local")); + let docdir = build.config.docdir.as_ref().clone().map(|x| Cow::Borrowed(Path::new(x))) + .unwrap_or(Cow::Owned(prefix.join("share/doc/rust"))); + let libdir = build.config.libdir.as_ref().clone().map(|x| Cow::Borrowed(Path::new(x))) + .unwrap_or(Cow::Owned(prefix.join("lib"))); + let mandir = build.config.mandir.as_ref().clone().map(|x| Cow::Borrowed(Path::new(x))) + .unwrap_or(Cow::Owned(prefix.join("share/man"))); + let empty_dir = build.out.join("tmp/empty_dir"); + t!(fs::create_dir_all(&empty_dir)); + if build.config.docs { + install_sh(&build, "docs", "rust-docs", stage, host, prefix, + &docdir, &libdir, &mandir, &empty_dir); + } + install_sh(&build, "std", "rust-std", stage, host, prefix, + &docdir, &libdir, &mandir, &empty_dir); + install_sh(&build, "rustc", "rustc", stage, host, prefix, + &docdir, &libdir, &mandir, &empty_dir); + t!(fs::remove_dir_all(&empty_dir)); +} + +fn install_sh(build: &Build, package: &str, name: &str, stage: u32, host: &str, + prefix: &Path, docdir: &Path, libdir: &Path, mandir: &Path, empty_dir: &Path) { + println!("Install {} stage{} ({})", package, stage, host); + let package_name = format!("{}-{}-{}", name, package_vers(build), host); + + let mut cmd = Command::new("sh"); + cmd.current_dir(empty_dir) + .arg(sanitize_sh(&tmpdir(build).join(&package_name).join("install.sh"))) + .arg(format!("--prefix={}", sanitize_sh(prefix))) + .arg(format!("--docdir={}", sanitize_sh(docdir))) + .arg(format!("--libdir={}", sanitize_sh(libdir))) + .arg(format!("--mandir={}", sanitize_sh(mandir))) + .arg("--disable-ldconfig"); + build.run(&mut cmd); +} diff --git a/src/bootstrap/lib.rs b/src/bootstrap/lib.rs index 32232cbee9..3f8e3fe531 100644 --- a/src/bootstrap/lib.rs +++ b/src/bootstrap/lib.rs @@ -26,7 +26,6 @@ extern crate md5; extern crate num_cpus; extern crate rustc_serialize; extern crate toml; -extern crate regex; use std::collections::HashMap; use std::env; @@ -58,10 +57,12 @@ mod channel; mod check; mod clean; mod compile; +mod metadata; mod config; mod dist; mod doc; mod flags; +mod install; mod native; mod sanity; mod step; @@ -76,7 +77,7 @@ mod job { } pub use config::Config; -pub use flags::Flags; +pub use flags::{Flags, Subcommand}; /// A structure representing a Rust compiler. /// @@ -123,13 +124,23 @@ pub struct Build { bootstrap_key_stage0: String, // Probed tools at runtime - gdb_version: Option, lldb_version: Option, lldb_python_dir: Option, // Runtime state filled in later on cc: HashMap)>, cxx: HashMap, + crates: HashMap, +} + +#[derive(Debug)] +struct Crate { + name: String, + deps: Vec, + path: PathBuf, + doc_step: String, + build_step: String, + test_step: String, } /// The various "modes" of invoking Cargo. @@ -162,7 +173,9 @@ impl Build { /// By default all build output will be placed in the current directory. pub fn new(flags: Flags, config: Config) -> Build { let cwd = t!(env::current_dir()); - let src = flags.src.clone().unwrap_or(cwd.clone()); + let src = flags.src.clone().or_else(|| { + env::var_os("SRC").map(|x| x.into()) + }).unwrap_or(cwd.clone()); let out = cwd.join("build"); let stage0_root = out.join(&config.build).join("stage0/bin"); @@ -196,7 +209,7 @@ impl Build { package_vers: String::new(), cc: HashMap::new(), cxx: HashMap::new(), - gdb_version: None, + crates: HashMap::new(), lldb_version: None, lldb_python_dir: None, } @@ -204,13 +217,11 @@ impl Build { /// Executes the entire build, as configured by the flags and configuration. pub fn build(&mut self) { - use step::Source::*; - unsafe { job::setup(); } - if self.flags.clean { + if let Subcommand::Clean = self.flags.cmd { return clean::clean(self); } @@ -220,257 +231,22 @@ impl Build { sanity::check(self); self.verbose("collecting channel variables"); channel::collect(self); - // If local-rust is the same as the current version, then force a local-rebuild + // If local-rust is the same major.minor as the current version, then force a local-rebuild let local_version_verbose = output( Command::new(&self.rustc).arg("--version").arg("--verbose")); let local_release = local_version_verbose .lines().filter(|x| x.starts_with("release:")) .next().unwrap().trim_left_matches("release:").trim(); - if local_release == self.release { - self.verbose(&format!("auto-detected local-rebuild {}", self.release)); + if local_release.split('.').take(2).eq(self.release.split('.').take(2)) { + self.verbose(&format!("auto-detected local-rebuild {}", local_release)); self.local_rebuild = true; } self.verbose("updating submodules"); self.update_submodules(); + self.verbose("learning about cargo"); + metadata::build(self); - // The main loop of the build system. - // - // The `step::all` function returns a topographically sorted list of all - // steps that need to be executed as part of this build. Each step has a - // corresponding entry in `step.rs` and indicates some unit of work that - // needs to be done as part of the build. - // - // Almost all of these are simple one-liners that shell out to the - // corresponding functionality in the extra modules, where more - // documentation can be found. - let steps = step::all(self); - - self.verbose("bootstrap build plan:"); - for step in &steps { - self.verbose(&format!("{:?}", step)); - } - - for target in steps { - let doc_out = self.out.join(&target.target).join("doc"); - match target.src { - Llvm { _dummy } => { - native::llvm(self, target.target); - } - TestHelpers { _dummy } => { - native::test_helpers(self, target.target); - } - Libstd { compiler } => { - compile::std(self, target.target, &compiler); - } - Libtest { compiler } => { - compile::test(self, target.target, &compiler); - } - Librustc { compiler } => { - compile::rustc(self, target.target, &compiler); - } - LibstdLink { compiler, host } => { - compile::std_link(self, target.target, &compiler, host); - } - LibtestLink { compiler, host } => { - compile::test_link(self, target.target, &compiler, host); - } - LibrustcLink { compiler, host } => { - compile::rustc_link(self, target.target, &compiler, host); - } - Rustc { stage: 0 } => { - // nothing to do... - } - Rustc { stage } => { - compile::assemble_rustc(self, stage, target.target); - } - ToolLinkchecker { stage } => { - compile::tool(self, stage, target.target, "linkchecker"); - } - ToolRustbook { stage } => { - compile::tool(self, stage, target.target, "rustbook"); - } - ToolErrorIndex { stage } => { - compile::tool(self, stage, target.target, - "error_index_generator"); - } - ToolCargoTest { stage } => { - compile::tool(self, stage, target.target, "cargotest"); - } - ToolTidy { stage } => { - compile::tool(self, stage, target.target, "tidy"); - } - ToolCompiletest { stage } => { - compile::tool(self, stage, target.target, "compiletest"); - } - DocBook { stage } => { - doc::rustbook(self, stage, target.target, "book", &doc_out); - } - DocNomicon { stage } => { - doc::rustbook(self, stage, target.target, "nomicon", - &doc_out); - } - DocStandalone { stage } => { - doc::standalone(self, stage, target.target, &doc_out); - } - DocStd { stage } => { - doc::std(self, stage, target.target, &doc_out); - } - DocTest { stage } => { - doc::test(self, stage, target.target, &doc_out); - } - DocRustc { stage } => { - doc::rustc(self, stage, target.target, &doc_out); - } - DocErrorIndex { stage } => { - doc::error_index(self, stage, target.target, &doc_out); - } - - CheckLinkcheck { stage } => { - check::linkcheck(self, stage, target.target); - } - CheckCargoTest { stage } => { - check::cargotest(self, stage, target.target); - } - CheckTidy { stage } => { - check::tidy(self, stage, target.target); - } - CheckRPass { compiler } => { - check::compiletest(self, &compiler, target.target, - "run-pass", "run-pass"); - } - CheckRPassFull { compiler } => { - check::compiletest(self, &compiler, target.target, - "run-pass", "run-pass-fulldeps"); - } - CheckCFail { compiler } => { - check::compiletest(self, &compiler, target.target, - "compile-fail", "compile-fail"); - } - CheckCFailFull { compiler } => { - check::compiletest(self, &compiler, target.target, - "compile-fail", "compile-fail-fulldeps") - } - CheckPFail { compiler } => { - check::compiletest(self, &compiler, target.target, - "parse-fail", "parse-fail"); - } - CheckRFail { compiler } => { - check::compiletest(self, &compiler, target.target, - "run-fail", "run-fail"); - } - CheckRFailFull { compiler } => { - check::compiletest(self, &compiler, target.target, - "run-fail", "run-fail-fulldeps"); - } - CheckPretty { compiler } => { - check::compiletest(self, &compiler, target.target, - "pretty", "pretty"); - } - CheckPrettyRPass { compiler } => { - check::compiletest(self, &compiler, target.target, - "pretty", "run-pass"); - } - CheckPrettyRPassFull { compiler } => { - check::compiletest(self, &compiler, target.target, - "pretty", "run-pass-fulldeps"); - } - CheckPrettyRFail { compiler } => { - check::compiletest(self, &compiler, target.target, - "pretty", "run-fail"); - } - CheckPrettyRFailFull { compiler } => { - check::compiletest(self, &compiler, target.target, - "pretty", "run-fail-fulldeps"); - } - CheckPrettyRPassValgrind { compiler } => { - check::compiletest(self, &compiler, target.target, - "pretty", "run-pass-valgrind"); - } - CheckMirOpt { compiler } => { - check::compiletest(self, &compiler, target.target, - "mir-opt", "mir-opt"); - } - CheckCodegen { compiler } => { - if self.config.codegen_tests { - check::compiletest(self, &compiler, target.target, - "codegen", "codegen"); - } - } - CheckCodegenUnits { compiler } => { - check::compiletest(self, &compiler, target.target, - "codegen-units", "codegen-units"); - } - CheckIncremental { compiler } => { - check::compiletest(self, &compiler, target.target, - "incremental", "incremental"); - } - CheckUi { compiler } => { - check::compiletest(self, &compiler, target.target, - "ui", "ui"); - } - CheckDebuginfo { compiler } => { - if target.target.contains("msvc") { - // nothing to do - } else if target.target.contains("apple") { - check::compiletest(self, &compiler, target.target, - "debuginfo-lldb", "debuginfo"); - } else { - check::compiletest(self, &compiler, target.target, - "debuginfo-gdb", "debuginfo"); - } - } - CheckRustdoc { compiler } => { - check::compiletest(self, &compiler, target.target, - "rustdoc", "rustdoc"); - } - CheckRPassValgrind { compiler } => { - check::compiletest(self, &compiler, target.target, - "run-pass-valgrind", "run-pass-valgrind"); - } - CheckDocs { compiler } => { - check::docs(self, &compiler); - } - CheckErrorIndex { compiler } => { - check::error_index(self, &compiler); - } - CheckRMake { compiler } => { - check::compiletest(self, &compiler, target.target, - "run-make", "run-make") - } - CheckCrateStd { compiler } => { - check::krate(self, &compiler, target.target, Mode::Libstd) - } - CheckCrateTest { compiler } => { - check::krate(self, &compiler, target.target, Mode::Libtest) - } - CheckCrateRustc { compiler } => { - check::krate(self, &compiler, target.target, Mode::Librustc) - } - - DistDocs { stage } => dist::docs(self, stage, target.target), - DistMingw { _dummy } => dist::mingw(self, target.target), - DistRustc { stage } => dist::rustc(self, stage, target.target), - DistStd { compiler } => dist::std(self, &compiler, target.target), - DistSrc { _dummy } => dist::rust_src(self), - - DebuggerScripts { stage } => { - let compiler = Compiler::new(stage, target.target); - dist::debugger_scripts(self, - &self.sysroot(&compiler), - target.target); - } - - AndroidCopyLibs { compiler } => { - check::android_copy_libs(self, &compiler, target.target); - } - - // pseudo-steps - Dist { .. } | - Doc { .. } | - CheckTarget { .. } | - Check { .. } => {} - } - } + step::run(self); } /// Updates all git submodules that we have. @@ -557,12 +333,23 @@ impl Build { continue } + // `submodule.path` is the relative path to a submodule (from the repository root) + // `submodule_path` is the path to a submodule from the cwd + + // use `submodule.path` when e.g. executing a submodule specific command from the + // repository root + // use `submodule_path` when e.g. executing a normal git command for the submodule + // (set via `current_dir`) + let submodule_path = self.src.join(submodule.path); + match submodule.state { State::MaybeDirty => { // drop staged changes - self.run(git().arg("-C").arg(submodule.path).args(&["reset", "--hard"])); + self.run(git().current_dir(&submodule_path) + .args(&["reset", "--hard"])); // drops unstaged changes - self.run(git().arg("-C").arg(submodule.path).args(&["clean", "-fdx"])); + self.run(git().current_dir(&submodule_path) + .args(&["clean", "-fdx"])); }, State::NotInitialized => { self.run(git_submodule().arg("init").arg(submodule.path)); @@ -571,8 +358,10 @@ impl Build { State::OutOfSync => { // drops submodule commits that weren't reported to the (outer) git repository self.run(git_submodule().arg("update").arg(submodule.path)); - self.run(git().arg("-C").arg(submodule.path).args(&["reset", "--hard"])); - self.run(git().arg("-C").arg(submodule.path).args(&["clean", "-fdx"])); + self.run(git().current_dir(&submodule_path) + .args(&["reset", "--hard"])); + self.run(git().current_dir(&submodule_path) + .args(&["clean", "-fdx"])); }, } } @@ -634,6 +423,7 @@ impl Build { .env("RUSTC_REAL", self.compiler_path(compiler)) .env("RUSTC_STAGE", stage.to_string()) .env("RUSTC_DEBUGINFO", self.config.rust_debuginfo.to_string()) + .env("RUSTC_DEBUGINFO_LINES", self.config.rust_debuginfo_lines.to_string()) .env("RUSTC_CODEGEN_UNITS", self.config.rust_codegen_units.to_string()) .env("RUSTC_DEBUG_ASSERTIONS", @@ -659,12 +449,6 @@ impl Build { .env(format!("CFLAGS_{}", target), self.cflags(target).join(" ")); } - // If we're building for OSX, inform the compiler and the linker that - // we want to build a compiler runnable on 10.7 - if target.contains("apple-darwin") { - cargo.env("MACOSX_DEPLOYMENT_TARGET", "10.7"); - } - // Environment variables *required* needed throughout the build // // FIXME: should update code to not require this env var @@ -802,6 +586,11 @@ impl Build { self.out.join(target).join("llvm") } + /// Output directory for all documentation for a target + fn doc_out(&self, target: &str) -> PathBuf { + self.out.join(target).join("doc") + } + /// Returns true if no custom `llvm-config` is set for the specified target. /// /// If no custom `llvm-config` was specified then Rust's llvm will be used. @@ -866,7 +655,7 @@ impl Build { cmd.env("RUSTC_BOOTSTRAP", "1"); // FIXME: Transitionary measure to bootstrap using the old bootstrap logic. // Remove this once the bootstrap compiler uses the new login in Issue #36548. - cmd.env("RUSTC_BOOTSTRAP_KEY", "5c6cf767"); + cmd.env("RUSTC_BOOTSTRAP_KEY", "62b3e239"); } /// Returns the compiler's libdir where it stores the dynamic libraries that @@ -928,7 +717,6 @@ impl Build { // LLVM/jemalloc/etc are all properly compiled. if target.contains("apple-darwin") { base.push("-stdlib=libc++".into()); - base.push("-mmacosx-version-min=10.7".into()); } // This is a hack, because newer binutils broke things on some vms/distros // (i.e., linking against unknown relocs disabled by the following flag) @@ -969,7 +757,8 @@ impl Build { // than an entry here. let mut base = Vec::new(); - if target != self.config.build && !target.contains("msvc") { + if target != self.config.build && !target.contains("msvc") && + !target.contains("emscripten") { base.push(format!("-Clinker={}", self.cc(target).display())); } return base @@ -977,7 +766,8 @@ impl Build { /// Returns the "musl root" for this `target`, if defined fn musl_root(&self, target: &str) -> Option<&Path> { - self.config.target_config[target].musl_root.as_ref() + self.config.target_config.get(target) + .and_then(|t| t.musl_root.as_ref()) .or(self.config.musl_root.as_ref()) .map(|p| &**p) } diff --git a/src/bootstrap/metadata.rs b/src/bootstrap/metadata.rs new file mode 100644 index 0000000000..bf5cc6a4ad --- /dev/null +++ b/src/bootstrap/metadata.rs @@ -0,0 +1,95 @@ +// Copyright 2016 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +use std::collections::HashMap; +use std::process::Command; +use std::path::PathBuf; + +use build_helper::output; +use rustc_serialize::json; + +use {Build, Crate}; + +#[derive(RustcDecodable)] +struct Output { + packages: Vec, + resolve: Resolve, +} + +#[derive(RustcDecodable)] +struct Package { + id: String, + name: String, + source: Option, + manifest_path: String, +} + +#[derive(RustcDecodable)] +struct Resolve { + nodes: Vec, +} + +#[derive(RustcDecodable)] +struct ResolveNode { + id: String, + dependencies: Vec, +} + +pub fn build(build: &mut Build) { + build_krate(build, "src/rustc/std_shim"); + build_krate(build, "src/rustc/test_shim"); + build_krate(build, "src/rustc"); +} + +fn build_krate(build: &mut Build, krate: &str) { + // Run `cargo metadata` to figure out what crates we're testing. + // + // Down below we're going to call `cargo test`, but to test the right set + // of packages we're going to have to know what `-p` arguments to pass it + // to know what crates to test. Here we run `cargo metadata` to learn about + // the dependency graph and what `-p` arguments there are. + let mut cargo = Command::new(&build.cargo); + cargo.arg("metadata") + .arg("--manifest-path").arg(build.src.join(krate).join("Cargo.toml")); + let output = output(&mut cargo); + let output: Output = json::decode(&output).unwrap(); + let mut id2name = HashMap::new(); + for package in output.packages { + if package.source.is_none() { + id2name.insert(package.id, package.name.clone()); + let mut path = PathBuf::from(package.manifest_path); + path.pop(); + build.crates.insert(package.name.clone(), Crate { + build_step: format!("build-crate-{}", package.name), + doc_step: format!("doc-crate-{}", package.name), + test_step: format!("test-crate-{}", package.name), + name: package.name, + deps: Vec::new(), + path: path, + }); + } + } + + for node in output.resolve.nodes { + let name = match id2name.get(&node.id) { + Some(name) => name, + None => continue, + }; + + let krate = build.crates.get_mut(name).unwrap(); + for dep in node.dependencies.iter() { + let dep = match id2name.get(dep) { + Some(dep) => dep, + None => continue, + }; + krate.deps.push(dep.clone()); + } + } +} diff --git a/src/bootstrap/mk/Makefile.in b/src/bootstrap/mk/Makefile.in index cc44d45c2c..d403107763 100644 --- a/src/bootstrap/mk/Makefile.in +++ b/src/bootstrap/mk/Makefile.in @@ -17,41 +17,46 @@ else BOOTSTRAP_ARGS := endif -BOOTSTRAP := $(CFG_PYTHON) $(CFG_SRC_DIR)src/bootstrap/bootstrap.py $(BOOTSTRAP_ARGS) +BOOTSTRAP := $(CFG_PYTHON) $(CFG_SRC_DIR)src/bootstrap/bootstrap.py all: - $(Q)$(BOOTSTRAP) + $(Q)$(BOOTSTRAP) build $(BOOTSTRAP_ARGS) + $(Q)$(BOOTSTRAP) doc $(BOOTSTRAP_ARGS) # Don’t use $(Q) here, always show how to invoke the bootstrap script directly help: $(BOOTSTRAP) --help clean: - $(Q)$(BOOTSTRAP) --clean + $(Q)$(BOOTSTRAP) clean $(BOOTSTRAP_ARGS) rustc-stage1: - $(Q)$(BOOTSTRAP) --step libtest --stage 1 + $(Q)$(BOOTSTRAP) build --stage 1 src/libtest $(BOOTSTRAP_ARGS) rustc-stage2: - $(Q)$(BOOTSTRAP) --step libtest --stage 2 + $(Q)$(BOOTSTRAP) build --stage 2 src/libtest $(BOOTSTRAP_ARGS) docs: doc doc: - $(Q)$(BOOTSTRAP) --step doc -style: - $(Q)$(BOOTSTRAP) --step doc-style + $(Q)$(BOOTSTRAP) doc $(BOOTSTRAP_ARGS) nomicon: - $(Q)$(BOOTSTRAP) --step doc-nomicon + $(Q)$(BOOTSTRAP) doc src/doc/nomicon $(BOOTSTRAP_ARGS) book: - $(Q)$(BOOTSTRAP) --step doc-book + $(Q)$(BOOTSTRAP) doc src/doc/book $(BOOTSTRAP_ARGS) standalone-docs: - $(Q)$(BOOTSTRAP) --step doc-standalone + $(Q)$(BOOTSTRAP) doc src/doc $(BOOTSTRAP_ARGS) check: - $(Q)$(BOOTSTRAP) --step check + $(Q)$(BOOTSTRAP) test $(BOOTSTRAP_ARGS) check-cargotest: - $(Q)$(BOOTSTRAP) --step check-cargotest + $(Q)$(BOOTSTRAP) test src/tools/cargotest $(BOOTSTRAP_ARGS) dist: - $(Q)$(BOOTSTRAP) --step dist + $(Q)$(BOOTSTRAP) dist $(BOOTSTRAP_ARGS) +install: +ifeq (root user, $(USER) $(patsubst %,user,$(SUDO_USER))) + $(Q)echo "'sudo make install' is not supported currently." +else + $(Q)$(BOOTSTRAP) dist --install $(BOOTSTRAP_ARGS) +endif tidy: - $(Q)$(BOOTSTRAP) --step check-tidy --stage 0 + $(Q)$(BOOTSTRAP) test src/tools/tidy $(BOOTSTRAP_ARGS) .PHONY: dist diff --git a/src/bootstrap/native.rs b/src/bootstrap/native.rs index df6408e5fe..1b4e86fb30 100644 --- a/src/bootstrap/native.rs +++ b/src/bootstrap/native.rs @@ -18,9 +18,10 @@ //! LLVM and compiler-rt are essentially just wired up to everything else to //! ensure that they're always in place if needed. +use std::fs::{self, File}; +use std::io::{Read, Write}; use std::path::Path; use std::process::Command; -use std::fs::{self, File}; use build_helper::output; use cmake; @@ -43,11 +44,17 @@ pub fn llvm(build: &Build, target: &str) { // artifacts are missing) then we keep going, otherwise we bail out. let dst = build.llvm_out(target); let stamp = build.src.join("src/rustllvm/llvm-auto-clean-trigger"); + let mut stamp_contents = String::new(); + t!(t!(File::open(&stamp)).read_to_string(&mut stamp_contents)); let done_stamp = dst.join("llvm-finished-building"); - build.clear_if_dirty(&dst, &stamp); - if fs::metadata(&done_stamp).is_ok() { - return + if done_stamp.exists() { + let mut done_contents = String::new(); + t!(t!(File::open(&done_stamp)).read_to_string(&mut done_contents)); + if done_contents == stamp_contents { + return + } } + drop(fs::remove_dir_all(&dst)); println!("Building LLVM for {}", target); @@ -65,7 +72,7 @@ pub fn llvm(build: &Build, target: &str) { .out_dir(&dst) .profile(if build.config.llvm_optimize {"Release"} else {"Debug"}) .define("LLVM_ENABLE_ASSERTIONS", assertions) - .define("LLVM_TARGETS_TO_BUILD", "X86;ARM;AArch64;Mips;PowerPC;SystemZ") + .define("LLVM_TARGETS_TO_BUILD", "X86;ARM;AArch64;Mips;PowerPC;SystemZ;JSBackend") .define("LLVM_INCLUDE_EXAMPLES", "OFF") .define("LLVM_INCLUDE_TESTS", "OFF") .define("LLVM_INCLUDE_DOCS", "OFF") @@ -73,7 +80,9 @@ pub fn llvm(build: &Build, target: &str) { .define("WITH_POLLY", "OFF") .define("LLVM_ENABLE_TERMINFO", "OFF") .define("LLVM_ENABLE_LIBEDIT", "OFF") - .define("LLVM_PARALLEL_COMPILE_JOBS", build.jobs().to_string()); + .define("LLVM_PARALLEL_COMPILE_JOBS", build.jobs().to_string()) + .define("LLVM_TARGET_ARCH", target.split('-').next().unwrap()) + .define("LLVM_DEFAULT_TARGET_TRIPLE", target); if target.starts_with("i686") { cfg.define("LLVM_BUILD_32_BITS", "ON"); @@ -86,9 +95,7 @@ pub fn llvm(build: &Build, target: &str) { // actually exists most of the time in normal installs of LLVM. let host = build.llvm_out(&build.config.build).join("bin/llvm-tblgen"); cfg.define("CMAKE_CROSSCOMPILING", "True") - .define("LLVM_TARGET_ARCH", target.split('-').next().unwrap()) - .define("LLVM_TABLEGEN", &host) - .define("LLVM_DEFAULT_TARGET_TRIPLE", target); + .define("LLVM_TABLEGEN", &host); } // MSVC handles compiler business itself @@ -114,7 +121,7 @@ pub fn llvm(build: &Build, target: &str) { // tools and libs on all platforms. cfg.build(); - t!(File::create(&done_stamp)); + t!(t!(File::create(&done_stamp)).write_all(stamp_contents.as_bytes())); } fn check_llvm_version(build: &Build, llvm_config: &Path) { diff --git a/src/bootstrap/sanity.rs b/src/bootstrap/sanity.rs index 05c35543e3..cc1b7136d4 100644 --- a/src/bootstrap/sanity.rs +++ b/src/bootstrap/sanity.rs @@ -40,17 +40,23 @@ pub fn check(build: &mut Build) { panic!("PATH contains invalid character '\"'"); } } - let mut need_cmd = |cmd: &OsStr| { - if !checked.insert(cmd.to_owned()) { - return - } + let have_cmd = |cmd: &OsStr| { for path in env::split_paths(&path).map(|p| p.join(cmd)) { if fs::metadata(&path).is_ok() || fs::metadata(path.with_extension("exe")).is_ok() { - return + return Some(path); } } - panic!("\n\ncouldn't find required command: {:?}\n\n", cmd); + return None; + }; + + let mut need_cmd = |cmd: &OsStr| { + if !checked.insert(cmd.to_owned()) { + return + } + if have_cmd(cmd).is_none() { + panic!("\n\ncouldn't find required command: {:?}\n\n", cmd); + } }; // If we've got a git directory we're gona need git to update @@ -75,15 +81,33 @@ pub fn check(build: &mut Build) { need_cmd("python".as_ref()); - // If a manual nodejs was added to the config, - // of if a nodejs install is detected through config, use it. + // Look for the nodejs command, needed for emscripten testing + if let Some(node) = have_cmd("node".as_ref()) { + build.config.nodejs = Some(node); + } else if let Some(node) = have_cmd("nodejs".as_ref()) { + build.config.nodejs = Some(node); + } + if let Some(ref s) = build.config.nodejs { need_cmd(s.as_ref()); } + if let Some(ref gdb) = build.config.gdb { + need_cmd(gdb.as_ref()); + } else { + build.config.gdb = have_cmd("gdb".as_ref()); + } + // We're gonna build some custom C code here and there, host triples // also build some C++ shims for LLVM so we need a C++ compiler. for target in build.config.target.iter() { + // On emscripten we don't actually need the C compiler to just + // build the target artifacts, only for testing. For the sake + // of easier bot configuration, just skip detection. + if target.contains("emscripten") { + continue; + } + need_cmd(build.cc(target).as_ref()); if let Some(ar) = build.ar(target) { need_cmd(ar.as_ref()); @@ -93,6 +117,14 @@ pub fn check(build: &mut Build) { need_cmd(build.cxx(host).as_ref()); } + // The msvc hosts don't use jemalloc, turn it off globally to + // avoid packaging the dummy liballoc_jemalloc on that platform. + for host in build.config.host.iter() { + if host.contains("msvc") { + build.config.use_jemalloc = false; + } + } + // Externally configured LLVM requires FileCheck to exist let filecheck = build.llvm_filecheck(&build.config.build); if !filecheck.starts_with(&build.out) && !filecheck.exists() && build.config.codegen_tests { @@ -100,15 +132,6 @@ pub fn check(build: &mut Build) { } for target in build.config.target.iter() { - // Either can't build or don't want to run jemalloc on these targets - if target.contains("rumprun") || - target.contains("bitrig") || - target.contains("openbsd") || - target.contains("msvc") || - target.contains("emscripten") { - build.config.use_jemalloc = false; - } - // Can't compile for iOS unless we're on OSX if target.contains("apple-ios") && !build.config.build.contains("apple-darwin") { @@ -129,8 +152,8 @@ pub fn check(build: &mut Build) { } } None => { - panic!("when targeting MUSL either the build.musl-root \ - option or the target.$TARGET.musl-root one must \ + panic!("when targeting MUSL either the rust.musl-root \ + option or the target.$TARGET.musl-root option must \ be specified in config.toml") } } @@ -181,7 +204,6 @@ $ pacman -R cmake && pacman -S mingw-w64-x86_64-cmake .to_string() }) }; - build.gdb_version = run(Command::new("gdb").arg("--version")).ok(); build.lldb_version = run(Command::new("lldb").arg("--version")).ok(); if build.lldb_version.is_some() { build.lldb_python_dir = run(Command::new("lldb").arg("-P")).ok(); diff --git a/src/bootstrap/step.rs b/src/bootstrap/step.rs index 4b5a26d205..56be2ccb23 100644 --- a/src/bootstrap/step.rs +++ b/src/bootstrap/step.rs @@ -8,592 +8,694 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -//! Major workhorse of rustbuild, definition and dependencies between stages of -//! the copmile. -//! -//! The primary purpose of this module is to define the various `Step`s of -//! execution of the build. Each `Step` has a corresponding `Source` indicating -//! what it's actually doing along with a number of dependencies which must be -//! executed first. -//! -//! This module will take the CLI as input and calculate the steps required for -//! the build requested, ensuring that all intermediate pieces are in place. -//! Essentially this module is a `make`-replacement, but not as good. - -use std::collections::HashSet; - -use {Build, Compiler}; - -#[derive(Hash, Eq, PartialEq, Clone, Debug)] -pub struct Step<'a> { - pub src: Source<'a>, - pub target: &'a str, +use std::collections::{HashMap, HashSet}; +use std::mem; + +use check; +use compile; +use dist; +use doc; +use flags::Subcommand; +use install; +use native; +use {Compiler, Build, Mode}; + +#[derive(PartialEq, Eq, Hash, Clone, Debug)] +struct Step<'a> { + name: &'a str, + stage: u32, + host: &'a str, + target: &'a str, } -/// Macro used to iterate over all targets that are recognized by the build -/// system. -/// -/// Whenever a new step is added it will involve adding an entry here, updating -/// the dependencies section below, and then adding an implementation of the -/// step in `build/mod.rs`. -/// -/// This macro takes another macro as an argument and then calls that macro with -/// all steps that the build system knows about. -macro_rules! targets { - ($m:ident) => { - $m! { - // Step representing building the stageN compiler. This is just the - // compiler executable itself, not any of the support libraries - (rustc, Rustc { stage: u32 }), - - // Steps for the two main cargo builds. These are parameterized over - // the compiler which is producing the artifact. - (libstd, Libstd { compiler: Compiler<'a> }), - (libtest, Libtest { compiler: Compiler<'a> }), - (librustc, Librustc { compiler: Compiler<'a> }), - - // Links the target produced by the compiler provided into the - // host's directory also provided. - (libstd_link, LibstdLink { - compiler: Compiler<'a>, - host: &'a str - }), - (libtest_link, LibtestLink { - compiler: Compiler<'a>, - host: &'a str - }), - (librustc_link, LibrustcLink { - compiler: Compiler<'a>, - host: &'a str - }), - - // Various tools that we can build as part of the build. - (tool_linkchecker, ToolLinkchecker { stage: u32 }), - (tool_rustbook, ToolRustbook { stage: u32 }), - (tool_error_index, ToolErrorIndex { stage: u32 }), - (tool_cargotest, ToolCargoTest { stage: u32 }), - (tool_tidy, ToolTidy { stage: u32 }), - (tool_compiletest, ToolCompiletest { stage: u32 }), - - // Steps for long-running native builds. Ideally these wouldn't - // actually exist and would be part of build scripts, but for now - // these are here. - // - // There aren't really any parameters to this, but empty structs - // with braces are unstable so we just pick something that works. - (llvm, Llvm { _dummy: () }), - (test_helpers, TestHelpers { _dummy: () }), - (debugger_scripts, DebuggerScripts { stage: u32 }), - - // Steps for various pieces of documentation that we can generate, - // the 'doc' step is just a pseudo target to depend on a bunch of - // others. - (doc, Doc { stage: u32 }), - (doc_book, DocBook { stage: u32 }), - (doc_nomicon, DocNomicon { stage: u32 }), - (doc_standalone, DocStandalone { stage: u32 }), - (doc_std, DocStd { stage: u32 }), - (doc_test, DocTest { stage: u32 }), - (doc_rustc, DocRustc { stage: u32 }), - (doc_error_index, DocErrorIndex { stage: u32 }), - - // Steps for running tests. The 'check' target is just a pseudo - // target to depend on a bunch of others. - (check, Check { stage: u32, compiler: Compiler<'a> }), - (check_target, CheckTarget { stage: u32, compiler: Compiler<'a> }), - (check_linkcheck, CheckLinkcheck { stage: u32 }), - (check_cargotest, CheckCargoTest { stage: u32 }), - (check_tidy, CheckTidy { stage: u32 }), - (check_rpass, CheckRPass { compiler: Compiler<'a> }), - (check_rpass_full, CheckRPassFull { compiler: Compiler<'a> }), - (check_rpass_valgrind, CheckRPassValgrind { compiler: Compiler<'a> }), - (check_rfail, CheckRFail { compiler: Compiler<'a> }), - (check_rfail_full, CheckRFailFull { compiler: Compiler<'a> }), - (check_cfail, CheckCFail { compiler: Compiler<'a> }), - (check_cfail_full, CheckCFailFull { compiler: Compiler<'a> }), - (check_pfail, CheckPFail { compiler: Compiler<'a> }), - (check_pretty, CheckPretty { compiler: Compiler<'a> }), - (check_pretty_rpass, CheckPrettyRPass { compiler: Compiler<'a> }), - (check_pretty_rpass_full, CheckPrettyRPassFull { compiler: Compiler<'a> }), - (check_pretty_rfail, CheckPrettyRFail { compiler: Compiler<'a> }), - (check_pretty_rfail_full, CheckPrettyRFailFull { compiler: Compiler<'a> }), - (check_pretty_rpass_valgrind, CheckPrettyRPassValgrind { compiler: Compiler<'a> }), - (check_codegen, CheckCodegen { compiler: Compiler<'a> }), - (check_codegen_units, CheckCodegenUnits { compiler: Compiler<'a> }), - (check_incremental, CheckIncremental { compiler: Compiler<'a> }), - (check_ui, CheckUi { compiler: Compiler<'a> }), - (check_mir_opt, CheckMirOpt { compiler: Compiler<'a> }), - (check_debuginfo, CheckDebuginfo { compiler: Compiler<'a> }), - (check_rustdoc, CheckRustdoc { compiler: Compiler<'a> }), - (check_docs, CheckDocs { compiler: Compiler<'a> }), - (check_error_index, CheckErrorIndex { compiler: Compiler<'a> }), - (check_rmake, CheckRMake { compiler: Compiler<'a> }), - (check_crate_std, CheckCrateStd { compiler: Compiler<'a> }), - (check_crate_test, CheckCrateTest { compiler: Compiler<'a> }), - (check_crate_rustc, CheckCrateRustc { compiler: Compiler<'a> }), - - // Distribution targets, creating tarballs - (dist, Dist { stage: u32 }), - (dist_docs, DistDocs { stage: u32 }), - (dist_mingw, DistMingw { _dummy: () }), - (dist_rustc, DistRustc { stage: u32 }), - (dist_std, DistStd { compiler: Compiler<'a> }), - (dist_src, DistSrc { _dummy: () }), - - // Misc targets - (android_copy_libs, AndroidCopyLibs { compiler: Compiler<'a> }), - } +impl<'a> Step<'a> { + fn name(&self, name: &'a str) -> Step<'a> { + Step { name: name, ..*self } } -} -// Define the `Source` enum by iterating over all the steps and peeling out just -// the types that we want to define. + fn stage(&self, stage: u32) -> Step<'a> { + Step { stage: stage, ..*self } + } -macro_rules! item { ($a:item) => ($a) } + fn host(&self, host: &'a str) -> Step<'a> { + Step { host: host, ..*self } + } -macro_rules! define_source { - ($(($short:ident, $name:ident { $($args:tt)* }),)*) => { - item! { - #[derive(Hash, Eq, PartialEq, Clone, Debug)] - pub enum Source<'a> { - $($name { $($args)* }),* - } - } + fn target(&self, target: &'a str) -> Step<'a> { + Step { target: target, ..*self } } -} -targets!(define_source); - -/// Calculate a list of all steps described by `build`. -/// -/// This will inspect the flags passed in on the command line and use that to -/// build up a list of steps to execute. These steps will then be transformed -/// into a topologically sorted list which when executed left-to-right will -/// correctly sequence the entire build. -pub fn all(build: &Build) -> Vec { - build.verbose("inferred build steps:"); - - let mut ret = Vec::new(); - let mut all = HashSet::new(); - for target in top_level(build) { - fill(build, &target, &mut ret, &mut all); - } - return ret; - - fn fill<'a>(build: &'a Build, - target: &Step<'a>, - ret: &mut Vec>, - set: &mut HashSet>) { - if set.insert(target.clone()) { - for dep in target.deps(build) { - build.verbose(&format!("{:?}\n -> {:?}", target, dep)); - fill(build, &dep, ret, set); - } - ret.push(target.clone()); - } + fn compiler(&self) -> Compiler<'a> { + Compiler::new(self.stage, self.host) } } -/// Determines what top-level targets are requested as part of this build, -/// returning them as a list. -fn top_level(build: &Build) -> Vec { - let mut targets = Vec::new(); - let stage = build.flags.stage.unwrap_or(2); +pub fn run(build: &Build) { + let rules = build_rules(build); + let steps = rules.plan(); + rules.run(&steps); +} - let host = Step { - src: Source::Llvm { _dummy: () }, - target: build.flags.host.iter().next() - .unwrap_or(&build.config.build), - }; - let target = Step { - src: Source::Llvm { _dummy: () }, - target: build.flags.target.iter().next().map(|x| &x[..]) - .unwrap_or(host.target) +pub fn build_rules(build: &Build) -> Rules { + let mut rules: Rules = Rules::new(build); + // dummy rule to do nothing, useful when a dep maps to no deps + rules.build("dummy", "path/to/nowhere"); + fn dummy<'a>(s: &Step<'a>, build: &'a Build) -> Step<'a> { + s.name("dummy").stage(0) + .target(&build.config.build) + .host(&build.config.build) + } + + // Helper for loading an entire DAG of crates, rooted at `name` + let krates = |name: &str| { + let mut ret = Vec::new(); + let mut list = vec![name]; + let mut visited = HashSet::new(); + while let Some(krate) = list.pop() { + let default = krate == name; + let krate = &build.crates[krate]; + let path = krate.path.strip_prefix(&build.src).unwrap(); + ret.push((krate, path.to_str().unwrap(), default)); + for dep in krate.deps.iter() { + if visited.insert(dep) && dep != "build_helper" { + list.push(dep); + } + } + } + return ret }; - // First, try to find steps on the command line. - add_steps(build, stage, &host, &target, &mut targets); + rules.build("rustc", "path/to/nowhere") + .dep(move |s| { + if s.stage == 0 { + dummy(s, build) + } else { + s.name("librustc") + .host(&build.config.build) + .stage(s.stage - 1) + } + }) + .run(move |s| compile::assemble_rustc(build, s.stage, s.target)); + rules.build("llvm", "src/llvm") + .host(true) + .run(move |s| native::llvm(build, s.target)); + + // ======================================================================== + // Crate compilations + // + // Tools used during the build system but not shipped + rules.build("libstd", "src/libstd") + .dep(|s| s.name("build-crate-std_shim")); + rules.build("libtest", "src/libtest") + .dep(|s| s.name("build-crate-test_shim")); + rules.build("librustc", "src/librustc") + .dep(|s| s.name("build-crate-rustc-main")); + for (krate, path, _default) in krates("std_shim") { + rules.build(&krate.build_step, path) + .dep(move |s| s.name("rustc").host(&build.config.build).target(s.host)) + .dep(move |s| { + if s.host == build.config.build { + dummy(s, build) + } else { + s.host(&build.config.build) + } + }) + .run(move |s| { + if s.host == build.config.build { + compile::std(build, s.target, &s.compiler()) + } else { + compile::std_link(build, s.target, s.stage, s.host) + } + }); + } + for (krate, path, default) in krates("test_shim") { + rules.build(&krate.build_step, path) + .dep(|s| s.name("libstd")) + .dep(move |s| { + if s.host == build.config.build { + dummy(s, build) + } else { + s.host(&build.config.build) + } + }) + .default(default) + .run(move |s| { + if s.host == build.config.build { + compile::test(build, s.target, &s.compiler()) + } else { + compile::test_link(build, s.target, s.stage, s.host) + } + }); + } + for (krate, path, default) in krates("rustc-main") { + rules.build(&krate.build_step, path) + .dep(|s| s.name("libtest")) + .dep(move |s| s.name("llvm").host(&build.config.build).stage(0)) + .dep(move |s| { + if s.host == build.config.build { + dummy(s, build) + } else { + s.host(&build.config.build) + } + }) + .host(true) + .default(default) + .run(move |s| { + if s.host == build.config.build { + compile::rustc(build, s.target, &s.compiler()) + } else { + compile::rustc_link(build, s.target, s.stage, s.host) + } + }); + } - // If none are specified, then build everything. - if targets.len() == 0 { - let t = Step { - src: Source::Llvm { _dummy: () }, - target: &build.config.build, + // ======================================================================== + // Test targets + // + // Various unit tests and tests suites we can run + { + let mut suite = |name, path, dir, mode| { + rules.test(name, path) + .dep(|s| s.name("libtest")) + .dep(|s| s.name("tool-compiletest").target(s.host)) + .dep(|s| s.name("test-helpers")) + .dep(move |s| { + if s.target.contains("android") { + s.name("android-copy-libs") + } else { + dummy(s, build) + } + }) + .default(true) + .run(move |s| { + check::compiletest(build, &s.compiler(), s.target, dir, mode) + }); }; - if build.config.docs { - targets.push(t.doc(stage)); - } - for host in build.config.host.iter() { - if !build.flags.host.contains(host) { - continue - } - let host = t.target(host); - if host.target == build.config.build { - targets.push(host.librustc(host.compiler(stage))); - } else { - targets.push(host.librustc_link(t.compiler(stage), host.target)); - } - for target in build.config.target.iter() { - if !build.flags.target.contains(target) { - continue - } - if host.target == build.config.build { - targets.push(host.target(target) - .libtest(host.compiler(stage))); - } else { - targets.push(host.target(target) - .libtest_link(t.compiler(stage), host.target)); - } - } + suite("check-rpass", "src/test/run-pass", "run-pass", "run-pass"); + suite("check-cfail", "src/test/compile-fail", "compile-fail", "compile-fail"); + suite("check-pfail", "src/test/parse-fail", "parse-fail", "parse-fail"); + suite("check-rfail", "src/test/run-fail", "run-fail", "run-fail"); + suite("check-rpass-valgrind", "src/test/run-pass-valgrind", + "run-pass-valgrind", "run-pass-valgrind"); + suite("check-mir-opt", "src/test/mir-opt", "mir-opt", "mir-opt"); + if build.config.codegen_tests { + suite("check-codegen", "src/test/codegen", "codegen", "codegen"); } + suite("check-codegen-units", "src/test/codegen-units", "codegen-units", + "codegen-units"); + suite("check-incremental", "src/test/incremental", "incremental", + "incremental"); + suite("check-ui", "src/test/ui", "ui", "ui"); + suite("check-pretty", "src/test/pretty", "pretty", "pretty"); + suite("check-pretty-rpass", "src/test/run-pass/pretty", "pretty", + "run-pass"); + suite("check-pretty-rfail", "src/test/run-pass/pretty", "pretty", + "run-fail"); + suite("check-pretty-valgrind", "src/test/run-pass-valgrind", "pretty", + "run-pass-valgrind"); + } + + if build.config.build.contains("msvc") { + // nothing to do for debuginfo tests + } else if build.config.build.contains("apple") { + rules.test("check-debuginfo", "src/test/debuginfo") + .dep(|s| s.name("libtest")) + .dep(|s| s.name("tool-compiletest").host(s.host)) + .dep(|s| s.name("test-helpers")) + .dep(|s| s.name("debugger-scripts")) + .run(move |s| check::compiletest(build, &s.compiler(), s.target, + "debuginfo-lldb", "debuginfo")); + } else { + rules.test("check-debuginfo", "src/test/debuginfo") + .dep(|s| s.name("libtest")) + .dep(|s| s.name("tool-compiletest").host(s.host)) + .dep(|s| s.name("test-helpers")) + .dep(|s| s.name("debugger-scripts")) + .run(move |s| check::compiletest(build, &s.compiler(), s.target, + "debuginfo-gdb", "debuginfo")); } - return targets + rules.test("debugger-scripts", "src/etc/lldb_batchmode.py") + .run(move |s| dist::debugger_scripts(build, &build.sysroot(&s.compiler()), + s.target)); + + { + let mut suite = |name, path, dir, mode| { + rules.test(name, path) + .dep(|s| s.name("librustc")) + .dep(|s| s.name("tool-compiletest").target(s.host)) + .default(true) + .host(true) + .run(move |s| { + check::compiletest(build, &s.compiler(), s.target, dir, mode) + }); + }; + + suite("check-rpass-full", "src/test/run-pass-fulldeps", + "run-pass", "run-pass-fulldeps"); + suite("check-cfail-full", "src/test/compile-fail-fulldeps", + "compile-fail", "compile-fail-fulldeps"); + suite("check-rmake", "src/test/run-make", "run-make", "run-make"); + suite("check-rustdoc", "src/test/rustdoc", "rustdoc", "rustdoc"); + suite("check-pretty-rpass-full", "src/test/run-pass-fulldeps", + "pretty", "run-pass-fulldeps"); + suite("check-pretty-rfail-full", "src/test/run-fail-fulldeps", + "pretty", "run-fail-fulldeps"); + } + for (krate, path, _default) in krates("std_shim") { + rules.test(&krate.test_step, path) + .dep(|s| s.name("libtest")) + .run(move |s| check::krate(build, &s.compiler(), s.target, + Mode::Libstd, Some(&krate.name))); + } + rules.test("check-std-all", "path/to/nowhere") + .dep(|s| s.name("libtest")) + .default(true) + .run(move |s| check::krate(build, &s.compiler(), s.target, Mode::Libstd, + None)); + for (krate, path, _default) in krates("test_shim") { + rules.test(&krate.test_step, path) + .dep(|s| s.name("libtest")) + .run(move |s| check::krate(build, &s.compiler(), s.target, + Mode::Libtest, Some(&krate.name))); + } + rules.test("check-test-all", "path/to/nowhere") + .dep(|s| s.name("libtest")) + .default(true) + .run(move |s| check::krate(build, &s.compiler(), s.target, Mode::Libtest, + None)); + for (krate, path, _default) in krates("rustc-main") { + rules.test(&krate.test_step, path) + .dep(|s| s.name("librustc")) + .host(true) + .run(move |s| check::krate(build, &s.compiler(), s.target, + Mode::Librustc, Some(&krate.name))); + } + rules.test("check-rustc-all", "path/to/nowhere") + .dep(|s| s.name("librustc")) + .default(true) + .host(true) + .run(move |s| check::krate(build, &s.compiler(), s.target, Mode::Librustc, + None)); + + rules.test("check-linkchecker", "src/tools/linkchecker") + .dep(|s| s.name("tool-linkchecker")) + .dep(|s| s.name("default:doc")) + .default(true) + .host(true) + .run(move |s| check::linkcheck(build, s.stage, s.target)); + rules.test("check-cargotest", "src/tools/cargotest") + .dep(|s| s.name("tool-cargotest")) + .dep(|s| s.name("librustc")) + .host(true) + .run(move |s| check::cargotest(build, s.stage, s.target)); + rules.test("check-tidy", "src/tools/tidy") + .dep(|s| s.name("tool-tidy")) + .default(true) + .host(true) + .run(move |s| check::tidy(build, s.stage, s.target)); + rules.test("check-error-index", "src/tools/error_index_generator") + .dep(|s| s.name("libstd")) + .dep(|s| s.name("tool-error-index").host(s.host)) + .default(true) + .host(true) + .run(move |s| check::error_index(build, &s.compiler())); + rules.test("check-docs", "src/doc") + .dep(|s| s.name("libtest")) + .default(true) + .host(true) + .run(move |s| check::docs(build, &s.compiler())); + + rules.build("test-helpers", "src/rt/rust_test_helpers.c") + .run(move |s| native::test_helpers(build, s.target)); + rules.test("android-copy-libs", "path/to/nowhere") + .dep(|s| s.name("libtest")) + .run(move |s| check::android_copy_libs(build, &s.compiler(), s.target)); + + // ======================================================================== + // Build tools + // + // Tools used during the build system but not shipped + rules.build("tool-rustbook", "src/tools/rustbook") + .dep(|s| s.name("librustc")) + .run(move |s| compile::tool(build, s.stage, s.target, "rustbook")); + rules.build("tool-error-index", "src/tools/error_index_generator") + .dep(|s| s.name("librustc")) + .run(move |s| compile::tool(build, s.stage, s.target, "error_index_generator")); + rules.build("tool-tidy", "src/tools/tidy") + .dep(|s| s.name("libstd")) + .run(move |s| compile::tool(build, s.stage, s.target, "tidy")); + rules.build("tool-linkchecker", "src/tools/linkchecker") + .dep(|s| s.name("libstd")) + .run(move |s| compile::tool(build, s.stage, s.target, "linkchecker")); + rules.build("tool-cargotest", "src/tools/cargotest") + .dep(|s| s.name("libstd")) + .run(move |s| compile::tool(build, s.stage, s.target, "cargotest")); + rules.build("tool-compiletest", "src/tools/compiletest") + .dep(|s| s.name("libtest")) + .run(move |s| compile::tool(build, s.stage, s.target, "compiletest")); + + // ======================================================================== + // Documentation targets + rules.doc("doc-book", "src/doc/book") + .dep(move |s| s.name("tool-rustbook").target(&build.config.build)) + .default(build.config.docs) + .run(move |s| doc::rustbook(build, s.stage, s.target, "book")); + rules.doc("doc-nomicon", "src/doc/nomicon") + .dep(move |s| s.name("tool-rustbook").target(&build.config.build)) + .default(build.config.docs) + .run(move |s| doc::rustbook(build, s.stage, s.target, "nomicon")); + rules.doc("doc-standalone", "src/doc") + .dep(move |s| s.name("rustc").host(&build.config.build).target(&build.config.build)) + .default(build.config.docs) + .run(move |s| doc::standalone(build, s.stage, s.target)); + rules.doc("doc-error-index", "src/tools/error_index_generator") + .dep(move |s| s.name("tool-error-index").target(&build.config.build)) + .dep(move |s| s.name("librustc")) + .default(build.config.docs) + .host(true) + .run(move |s| doc::error_index(build, s.stage, s.target)); + for (krate, path, default) in krates("std_shim") { + rules.doc(&krate.doc_step, path) + .dep(|s| s.name("libstd")) + .default(default && build.config.docs) + .run(move |s| doc::std(build, s.stage, s.target)); + } + for (krate, path, default) in krates("test_shim") { + rules.doc(&krate.doc_step, path) + .dep(|s| s.name("libtest")) + .default(default && build.config.docs) + .run(move |s| doc::test(build, s.stage, s.target)); + } + for (krate, path, default) in krates("rustc-main") { + rules.doc(&krate.doc_step, path) + .dep(|s| s.name("librustc")) + .host(true) + .default(default && build.config.compiler_docs) + .run(move |s| doc::rustc(build, s.stage, s.target)); + } + + // ======================================================================== + // Distribution targets + rules.dist("dist-rustc", "src/librustc") + .dep(move |s| s.name("rustc").host(&build.config.build)) + .host(true) + .default(true) + .run(move |s| dist::rustc(build, s.stage, s.target)); + rules.dist("dist-std", "src/libstd") + .dep(move |s| { + // We want to package up as many target libraries as possible + // for the `rust-std` package, so if this is a host target we + // depend on librustc and otherwise we just depend on libtest. + if build.config.host.iter().any(|t| t == s.target) { + s.name("librustc") + } else { + s.name("libtest") + } + }) + .default(true) + .run(move |s| dist::std(build, &s.compiler(), s.target)); + rules.dist("dist-mingw", "path/to/nowhere") + .run(move |s| dist::mingw(build, s.target)); + rules.dist("dist-src", "src") + .default(true) + .host(true) + .run(move |_| dist::rust_src(build)); + rules.dist("dist-docs", "src/doc") + .default(true) + .dep(|s| s.name("default:doc")) + .run(move |s| dist::docs(build, s.stage, s.target)); + rules.dist("install", "src") + .dep(|s| s.name("default:dist")) + .run(move |s| install::install(build, s.stage, s.target)); + + rules.verify(); + return rules } -fn add_steps<'a>(build: &'a Build, - stage: u32, - host: &Step<'a>, - target: &Step<'a>, - targets: &mut Vec>) { - struct Context<'a> { - stage: u32, - compiler: Compiler<'a>, - _dummy: (), - host: &'a str, - } - for step in build.flags.step.iter() { - - // The macro below insists on hygienic access to all local variables, so - // we shove them all in a struct and subvert hygiene by accessing struct - // fields instead, - let cx = Context { - stage: stage, - compiler: host.target(&build.config.build).compiler(stage), - _dummy: (), - host: host.target, - }; - macro_rules! add_step { - ($(($short:ident, $name:ident { $($arg:ident: $t:ty),* }),)*) => ({$( - let name = stringify!($short).replace("_", "-"); - if &step[..] == &name[..] { - targets.push(target.$short($(cx.$arg),*)); - continue - } - drop(name); - )*}) +struct Rule<'a> { + name: &'a str, + path: &'a str, + kind: Kind, + deps: Vec) -> Step<'a> + 'a>>, + run: Box) + 'a>, + default: bool, + host: bool, +} + +#[derive(PartialEq)] +enum Kind { + Build, + Test, + Dist, + Doc, +} + +impl<'a> Rule<'a> { + fn new(name: &'a str, path: &'a str, kind: Kind) -> Rule<'a> { + Rule { + name: name, + deps: Vec::new(), + run: Box::new(|_| ()), + path: path, + kind: kind, + default: false, + host: false, } + } +} + +struct RuleBuilder<'a: 'b, 'b> { + rules: &'b mut Rules<'a>, + rule: Rule<'a>, +} - targets!(add_step); +impl<'a, 'b> RuleBuilder<'a, 'b> { + fn dep(&mut self, f: F) -> &mut Self + where F: Fn(&Step<'a>) -> Step<'a> + 'a, + { + self.rule.deps.push(Box::new(f)); + self + } - panic!("unknown step: {}", step); + fn run(&mut self, f: F) -> &mut Self + where F: Fn(&Step<'a>) + 'a, + { + self.rule.run = Box::new(f); + self + } + + fn default(&mut self, default: bool) -> &mut Self { + self.rule.default = default; + self + } + + fn host(&mut self, host: bool) -> &mut Self { + self.rule.host = host; + self } } -macro_rules! constructors { - ($(($short:ident, $name:ident { $($arg:ident: $t:ty),* }),)*) => {$( - fn $short(&self, $($arg: $t),*) -> Step<'a> { - Step { - src: Source::$name { $($arg: $arg),* }, - target: self.target, - } +impl<'a, 'b> Drop for RuleBuilder<'a, 'b> { + fn drop(&mut self) { + let rule = mem::replace(&mut self.rule, Rule::new("", "", Kind::Build)); + let prev = self.rules.rules.insert(rule.name, rule); + if let Some(prev) = prev { + panic!("duplicate rule named: {}", prev.name); } - )*} + } } -impl<'a> Step<'a> { - fn compiler(&self, stage: u32) -> Compiler<'a> { - Compiler::new(stage, self.target) +pub struct Rules<'a> { + build: &'a Build, + sbuild: Step<'a>, + rules: HashMap<&'a str, Rule<'a>>, +} + +impl<'a> Rules<'a> { + fn new(build: &'a Build) -> Rules<'a> { + Rules { + build: build, + sbuild: Step { + stage: build.flags.stage.unwrap_or(2), + target: &build.config.build, + host: &build.config.build, + name: "", + }, + rules: HashMap::new(), + } } - fn target(&self, target: &'a str) -> Step<'a> { - Step { target: target, src: self.src.clone() } + fn build<'b>(&'b mut self, name: &'a str, path: &'a str) + -> RuleBuilder<'a, 'b> { + self.rule(name, path, Kind::Build) } - // Define ergonomic constructors for each step defined above so they can be - // easily constructed. - targets!(constructors); + fn test<'b>(&'b mut self, name: &'a str, path: &'a str) + -> RuleBuilder<'a, 'b> { + self.rule(name, path, Kind::Test) + } - /// Mapping of all dependencies for rustbuild. - /// - /// This function receives a step, the build that we're building for, and - /// then returns a list of all the dependencies of that step. - pub fn deps(&self, build: &'a Build) -> Vec> { - match self.src { - Source::Rustc { stage: 0 } => { - Vec::new() - } - Source::Rustc { stage } => { - let compiler = Compiler::new(stage - 1, &build.config.build); - vec![self.librustc(compiler)] - } - Source::Librustc { compiler } => { - vec![self.libtest(compiler), self.llvm(())] - } - Source::Libtest { compiler } => { - vec![self.libstd(compiler)] - } - Source::Libstd { compiler } => { - vec![self.rustc(compiler.stage).target(compiler.host)] - } - Source::LibrustcLink { compiler, host } => { - vec![self.librustc(compiler), - self.libtest_link(compiler, host)] - } - Source::LibtestLink { compiler, host } => { - vec![self.libtest(compiler), self.libstd_link(compiler, host)] - } - Source::LibstdLink { compiler, host } => { - vec![self.libstd(compiler), - self.target(host).rustc(compiler.stage)] - } - Source::Llvm { _dummy } => Vec::new(), - Source::TestHelpers { _dummy } => Vec::new(), - Source::DebuggerScripts { stage: _ } => Vec::new(), - - // Note that all doc targets depend on artifacts from the build - // architecture, not the target (which is where we're generating - // docs into). - Source::DocStd { stage } => { - let compiler = self.target(&build.config.build).compiler(stage); - vec![self.libstd(compiler)] - } - Source::DocTest { stage } => { - let compiler = self.target(&build.config.build).compiler(stage); - vec![self.libtest(compiler)] - } - Source::DocBook { stage } | - Source::DocNomicon { stage } => { - vec![self.target(&build.config.build).tool_rustbook(stage)] - } - Source::DocErrorIndex { stage } => { - vec![self.target(&build.config.build).tool_error_index(stage)] - } - Source::DocStandalone { stage } => { - vec![self.target(&build.config.build).rustc(stage)] - } - Source::DocRustc { stage } => { - vec![self.doc_test(stage)] - } - Source::Doc { stage } => { - let mut deps = vec![ - self.doc_book(stage), self.doc_nomicon(stage), - self.doc_standalone(stage), self.doc_std(stage), - self.doc_error_index(stage), - ]; - - if build.config.compiler_docs { - deps.push(self.doc_rustc(stage)); - } + fn doc<'b>(&'b mut self, name: &'a str, path: &'a str) + -> RuleBuilder<'a, 'b> { + self.rule(name, path, Kind::Doc) + } - deps - } - Source::Check { stage, compiler } => { - // Check is just a pseudo step which means check all targets, - // so just depend on checking all targets. - build.config.target.iter().map(|t| { - self.target(t).check_target(stage, compiler) - }).collect() - } - Source::CheckTarget { stage, compiler } => { - // CheckTarget here means run all possible test suites for this - // target. Most of the time, however, we can't actually run - // anything if we're not the build triple as we could be cross - // compiling. - // - // As a result, the base set of targets here is quite stripped - // down from the standard set of targets. These suites have - // their own internal logic to run in cross-compiled situations - // if they'll run at all. For example compiletest knows that - // when testing Android targets we ship artifacts to the - // emulator. - // - // When in doubt the rule of thumb for adding to this list is - // "should this test suite run on the android bot?" - let mut base = vec![ - self.check_rpass(compiler), - self.check_rfail(compiler), - self.check_crate_std(compiler), - self.check_crate_test(compiler), - self.check_debuginfo(compiler), - self.dist(stage), - ]; - - // If we're testing the build triple, then we know we can - // actually run binaries and such, so we run all possible tests - // that we know about. - if self.target == build.config.build { - base.extend(vec![ - // docs-related - self.check_docs(compiler), - self.check_error_index(compiler), - self.check_rustdoc(compiler), - - // UI-related - self.check_cfail(compiler), - self.check_pfail(compiler), - self.check_ui(compiler), - - // codegen-related - self.check_incremental(compiler), - self.check_codegen(compiler), - self.check_codegen_units(compiler), - - // misc compiletest-test suites - self.check_rpass_full(compiler), - self.check_rfail_full(compiler), - self.check_cfail_full(compiler), - self.check_pretty_rpass_full(compiler), - self.check_pretty_rfail_full(compiler), - self.check_rpass_valgrind(compiler), - self.check_rmake(compiler), - self.check_mir_opt(compiler), - - // crates - self.check_crate_rustc(compiler), - - // pretty - self.check_pretty(compiler), - self.check_pretty_rpass(compiler), - self.check_pretty_rfail(compiler), - self.check_pretty_rpass_valgrind(compiler), - - // misc - self.check_linkcheck(stage), - self.check_tidy(stage), - ]); - } - return base - } - Source::CheckLinkcheck { stage } => { - vec![self.tool_linkchecker(stage), self.doc(stage)] - } - Source::CheckCargoTest { stage } => { - vec![self.tool_cargotest(stage), - self.librustc(self.compiler(stage))] - } - Source::CheckTidy { stage } => { - vec![self.tool_tidy(stage)] - } - Source::CheckMirOpt { compiler} | - Source::CheckPrettyRPass { compiler } | - Source::CheckPrettyRFail { compiler } | - Source::CheckRFail { compiler } | - Source::CheckPFail { compiler } | - Source::CheckCodegen { compiler } | - Source::CheckCodegenUnits { compiler } | - Source::CheckIncremental { compiler } | - Source::CheckUi { compiler } | - Source::CheckRustdoc { compiler } | - Source::CheckPretty { compiler } | - Source::CheckCFail { compiler } | - Source::CheckRPassValgrind { compiler } | - Source::CheckRPass { compiler } => { - let mut base = vec![ - self.libtest(compiler), - self.target(compiler.host).tool_compiletest(compiler.stage), - self.test_helpers(()), - ]; - if self.target.contains("android") { - base.push(self.android_copy_libs(compiler)); + fn dist<'b>(&'b mut self, name: &'a str, path: &'a str) + -> RuleBuilder<'a, 'b> { + self.rule(name, path, Kind::Dist) + } + + fn rule<'b>(&'b mut self, + name: &'a str, + path: &'a str, + kind: Kind) -> RuleBuilder<'a, 'b> { + RuleBuilder { + rules: self, + rule: Rule::new(name, path, kind), + } + } + + /// Verify the dependency graph defined by all our rules are correct, e.g. + /// everything points to a valid something else. + fn verify(&self) { + for rule in self.rules.values() { + for dep in rule.deps.iter() { + let dep = dep(&self.sbuild.name(rule.name)); + if self.rules.contains_key(&dep.name) || dep.name.starts_with("default:") { + continue } - base - } - Source::CheckDebuginfo { compiler } => { - vec![ - self.libtest(compiler), - self.target(compiler.host).tool_compiletest(compiler.stage), - self.test_helpers(()), - self.debugger_scripts(compiler.stage), - ] - } - Source::CheckRPassFull { compiler } | - Source::CheckRFailFull { compiler } | - Source::CheckCFailFull { compiler } | - Source::CheckPrettyRPassFull { compiler } | - Source::CheckPrettyRFailFull { compiler } | - Source::CheckPrettyRPassValgrind { compiler } | - Source::CheckRMake { compiler } => { - vec![self.librustc(compiler), - self.target(compiler.host).tool_compiletest(compiler.stage)] - } - Source::CheckDocs { compiler } => { - vec![self.libstd(compiler)] - } - Source::CheckErrorIndex { compiler } => { - vec![self.libstd(compiler), - self.target(compiler.host).tool_error_index(compiler.stage)] - } - Source::CheckCrateStd { compiler } => { - vec![self.libtest(compiler)] - } - Source::CheckCrateTest { compiler } => { - vec![self.libtest(compiler)] - } - Source::CheckCrateRustc { compiler } => { - vec![self.libtest(compiler)] - } + panic!("\ - Source::ToolLinkchecker { stage } | - Source::ToolTidy { stage } => { - vec![self.libstd(self.compiler(stage))] - } - Source::ToolErrorIndex { stage } | - Source::ToolRustbook { stage } => { - vec![self.librustc(self.compiler(stage))] - } - Source::ToolCargoTest { stage } => { - vec![self.libstd(self.compiler(stage))] - } - Source::ToolCompiletest { stage } => { - vec![self.libtest(self.compiler(stage))] - } +invalid rule dependency graph detected, was a rule added and maybe typo'd? + + `{}` depends on `{}` which does not exist - Source::DistDocs { stage } => vec![self.doc(stage)], - Source::DistMingw { _dummy: _ } => Vec::new(), - Source::DistRustc { stage } => { - vec![self.rustc(stage)] +", rule.name, dep.name); } - Source::DistStd { compiler } => { - // We want to package up as many target libraries as possible - // for the `rust-std` package, so if this is a host target we - // depend on librustc and otherwise we just depend on libtest. - if build.config.host.iter().any(|t| t == self.target) { - vec![self.librustc(compiler)] + } + } + + pub fn print_help(&self, command: &str) { + let kind = match command { + "build" => Kind::Build, + "doc" => Kind::Doc, + "test" => Kind::Test, + "dist" => Kind::Dist, + _ => return, + }; + let rules = self.rules.values().filter(|r| r.kind == kind); + let rules = rules.filter(|r| !r.path.contains("nowhere")); + let mut rules = rules.collect::>(); + rules.sort_by_key(|r| r.path); + + println!("Available paths:\n"); + for rule in rules { + print!(" ./x.py {} {}", command, rule.path); + + println!(""); + } + } + + /// Construct the top-level build steps that we're going to be executing, + /// given the subcommand that our build is performing. + fn plan(&self) -> Vec> { + let (kind, paths) = match self.build.flags.cmd { + Subcommand::Build { ref paths } => (Kind::Build, &paths[..]), + Subcommand::Doc { ref paths } => (Kind::Doc, &paths[..]), + Subcommand::Test { ref paths, test_args: _ } => (Kind::Test, &paths[..]), + Subcommand::Dist { install } => { + if install { + return vec![self.sbuild.name("install")] } else { - vec![self.libtest(compiler)] - } - } - Source::DistSrc { _dummy: _ } => Vec::new(), - - Source::Dist { stage } => { - let mut base = Vec::new(); - - for host in build.config.host.iter() { - let host = self.target(host); - base.push(host.dist_src(())); - base.push(host.dist_rustc(stage)); - if host.target.contains("windows-gnu") { - base.push(host.dist_mingw(())); - } - - let compiler = self.compiler(stage); - for target in build.config.target.iter() { - let target = self.target(target); - if build.config.docs { - base.push(target.dist_docs(stage)); - } - base.push(target.dist_std(compiler)); - } + (Kind::Dist, &[][..]) } - return base } + Subcommand::Clean => panic!(), + }; - Source::AndroidCopyLibs { compiler } => { - vec![self.libtest(compiler)] + self.rules.values().filter(|rule| rule.kind == kind).filter(|rule| { + (paths.len() == 0 && rule.default) || paths.iter().any(|path| { + path.ends_with(rule.path) + }) + }).flat_map(|rule| { + let hosts = if self.build.flags.host.len() > 0 { + &self.build.flags.host + } else { + &self.build.config.host + }; + let targets = if self.build.flags.target.len() > 0 { + &self.build.flags.target + } else { + &self.build.config.target + }; + let arr = if rule.host {hosts} else {targets}; + + hosts.iter().flat_map(move |host| { + arr.iter().map(move |target| { + self.sbuild.name(rule.name).target(target).host(host) + }) + }) + }).collect() + } + + /// Execute all top-level targets indicated by `steps`. + /// + /// This will take the list returned by `plan` and then execute each step + /// along with all required dependencies as it goes up the chain. + fn run(&self, steps: &[Step<'a>]) { + self.build.verbose("bootstrap top targets:"); + for step in steps.iter() { + self.build.verbose(&format!("\t{:?}", step)); + } + + // Using `steps` as the top-level targets, make a topological ordering + // of what we need to do. + let mut order = Vec::new(); + let mut added = HashSet::new(); + for step in steps.iter().cloned() { + self.fill(step, &mut order, &mut added); + } + + // Print out what we're doing for debugging + self.build.verbose("bootstrap build plan:"); + for step in order.iter() { + self.build.verbose(&format!("\t{:?}", step)); + } + + // And finally, iterate over everything and execute it. + for step in order.iter() { + self.build.verbose(&format!("executing step {:?}", step)); + (self.rules[step.name].run)(step); + } + } + + fn fill(&self, + step: Step<'a>, + order: &mut Vec>, + added: &mut HashSet>) { + if !added.insert(step.clone()) { + return + } + for dep in self.rules[step.name].deps.iter() { + let dep = dep(&step); + if dep.name.starts_with("default:") { + let kind = match &dep.name[8..] { + "doc" => Kind::Doc, + "dist" => Kind::Dist, + kind => panic!("unknown kind: `{}`", kind), + }; + let host = self.build.config.host.iter().any(|h| h == dep.target); + let rules = self.rules.values().filter(|r| r.default); + for rule in rules.filter(|r| r.kind == kind && (!r.host || host)) { + self.fill(dep.name(rule.name), order, added); + } + } else { + self.fill(dep, order, added); } } + order.push(step); } } diff --git a/src/bootstrap/util.rs b/src/bootstrap/util.rs index 6c0a32a54d..e028c52236 100644 --- a/src/bootstrap/util.rs +++ b/src/bootstrap/util.rs @@ -57,8 +57,7 @@ pub fn cp_r(src: &Path, dst: &Path) { let name = path.file_name().unwrap(); let dst = dst.join(name); if t!(f.file_type()).is_dir() { - let _ = fs::remove_dir_all(&dst); - t!(fs::create_dir(&dst)); + t!(fs::create_dir_all(&dst)); cp_r(&path, &dst); } else { let _ = fs::remove_file(&dst); @@ -172,3 +171,21 @@ pub fn dylib_path() -> Vec { env::split_paths(&env::var_os(dylib_path_var()).unwrap_or(OsString::new())) .collect() } + +/// `push` all components to `buf`. On windows, append `.exe` to the last component. +pub fn push_exe_path(mut buf: PathBuf, components: &[&str]) -> PathBuf { + let (&file, components) = components.split_last().expect("at least one component required"); + let mut file = file.to_owned(); + + if cfg!(windows) { + file.push_str(".exe"); + } + + for c in components { + buf.push(c); + } + + buf.push(file); + + buf +} diff --git a/src/build_helper/lib.rs b/src/build_helper/lib.rs index 838cc4f07a..38844fb6c9 100644 --- a/src/build_helper/lib.rs +++ b/src/build_helper/lib.rs @@ -25,7 +25,9 @@ pub fn run_silent(cmd: &mut Command) { }; if !status.success() { fail(&format!("command did not execute successfully: {:?}\n\ - expected success, got: {}", cmd, status)); + expected success, got: {}", + cmd, + status)); } } @@ -65,7 +67,9 @@ pub fn output(cmd: &mut Command) -> String { }; if !output.status.success() { panic!("command did not execute successfully: {:?}\n\ - expected success, got: {}", cmd, output.status); + expected success, got: {}", + cmd, + output.status); } String::from_utf8(output.stdout).unwrap() } diff --git a/src/compiler-rt/lib/builtins/int_lib.h b/src/compiler-rt/lib/builtins/int_lib.h index 6cf17497d3..8dfe5672d1 100644 --- a/src/compiler-rt/lib/builtins/int_lib.h +++ b/src/compiler-rt/lib/builtins/int_lib.h @@ -32,7 +32,7 @@ #if __ARM_EABI__ # define ARM_EABI_FNALIAS(aeabi_name, name) \ void __aeabi_##aeabi_name() __attribute__((alias("__" #name))); -# define COMPILER_RT_ABI +# define COMPILER_RT_ABI __attribute__((pcs("aapcs"))) #else # define ARM_EABI_FNALIAS(aeabi_name, name) # define COMPILER_RT_ABI diff --git a/src/compiler-rt/lib/builtins/powidf2.c b/src/compiler-rt/lib/builtins/powidf2.c index ac13b172b0..0200e1eab0 100644 --- a/src/compiler-rt/lib/builtins/powidf2.c +++ b/src/compiler-rt/lib/builtins/powidf2.c @@ -16,7 +16,7 @@ /* Returns: a ^ b */ -COMPILER_RT_ABI double +double __powidf2(double a, si_int b) { const int recip = b < 0; diff --git a/src/compiler-rt/lib/builtins/powisf2.c b/src/compiler-rt/lib/builtins/powisf2.c index 0c400ec6dd..c834b96969 100644 --- a/src/compiler-rt/lib/builtins/powisf2.c +++ b/src/compiler-rt/lib/builtins/powisf2.c @@ -16,7 +16,7 @@ /* Returns: a ^ b */ -COMPILER_RT_ABI float +float __powisf2(float a, si_int b) { const int recip = b < 0; diff --git a/src/doc/book/closures.md b/src/doc/book/closures.md index 3ed85c1a90..fa9f66d43b 100644 --- a/src/doc/book/closures.md +++ b/src/doc/book/closures.md @@ -327,7 +327,7 @@ that takes a reference like so: fn call_with_ref(some_closure:F) -> i32 where F: Fn(&i32) -> i32 { - let mut value = 0; + let value = 0; some_closure(&value) } ``` @@ -340,14 +340,15 @@ fn call_with_ref<'a, F>(some_closure:F) -> i32 where F: Fn(&'a i32) -> i32 { ``` -However this presents a problem in our case. When you specify the explicit -lifetime on a function it binds that lifetime to the *entire* scope of the function -instead of just the invocation scope of our closure. This means that the borrow checker -will see a mutable reference in the same lifetime as our immutable reference and fail -to compile. +However, this presents a problem in our case. When a function has an explicit +lifetime parameter, that lifetime must be at least as long as the *entire* +call to that function. The borrow checker will complain that `value` doesn't +live long enough, because it is only in scope after its declaration inside the +function body. -In order to say that we only need the lifetime to be valid for the invocation scope -of the closure we can use Higher-Ranked Trait Bounds with the `for<...>` syntax: +What we need is a closure that can borrow its argument only for its own +invocation scope, not for the outer function's scope. In order to say that, +we can use Higher-Ranked Trait Bounds with the `for<...>` syntax: ```ignore fn call_with_ref(some_closure:F) -> i32 @@ -362,7 +363,7 @@ expect. fn call_with_ref(some_closure:F) -> i32 where F: for<'a> Fn(&'a i32) -> i32 { - let mut value = 0; + let value = 0; some_closure(&value) } ``` @@ -510,12 +511,11 @@ fn factory() -> Box i32> { Box::new(|x| x + num) } -# fn main() { + let f = factory(); let answer = f(1); assert_eq!(6, answer); -# } ``` There’s just one last problem: @@ -540,12 +540,11 @@ fn factory() -> Box i32> { Box::new(move |x| x + num) } -fn main() { + let f = factory(); let answer = f(1); assert_eq!(6, answer); -} ``` By making the inner closure a `move Fn`, we create a new stack frame for our diff --git a/src/doc/book/concurrency.md b/src/doc/book/concurrency.md index a783650f8e..41d8345b72 100644 --- a/src/doc/book/concurrency.md +++ b/src/doc/book/concurrency.md @@ -4,7 +4,7 @@ Concurrency and parallelism are incredibly important topics in computer science, and are also a hot topic in industry today. Computers are gaining more and more cores, yet many programmers aren't prepared to fully utilize them. -Rust's memory safety features also apply to its concurrency story too. Even +Rust's memory safety features also apply to its concurrency story. Even concurrent Rust programs must be memory safe, having no data races. Rust's type system is up to the task, and gives you powerful ways to reason about concurrent code at compile time. @@ -281,8 +281,8 @@ And... still gives us an error. ``` `Arc` by default has immutable contents. It allows the _sharing_ of data -between threads, but shared mutable data is unsafe and when threads are -involved can cause data races! +between threads, but shared mutable data is unsafe—and when threads are +involved—can cause data races! Usually when we wish to make something in an immutable position mutable, we use diff --git a/src/doc/book/const-and-static.md b/src/doc/book/const-and-static.md index 11aa25ac81..e8f17a41cb 100644 --- a/src/doc/book/const-and-static.md +++ b/src/doc/book/const-and-static.md @@ -1,4 +1,4 @@ -% `const` and `static` +% const and static Rust has a way of defining constants with the `const` keyword: diff --git a/src/doc/book/deref-coercions.md b/src/doc/book/deref-coercions.md index beb65c4ce3..cabe66f5b2 100644 --- a/src/doc/book/deref-coercions.md +++ b/src/doc/book/deref-coercions.md @@ -69,7 +69,7 @@ foo(&counted); All we’ve done is wrap our `String` in an `Rc`. But we can now pass the `Rc` around anywhere we’d have a `String`. The signature of `foo` didn’t change, but works just as well with either type. This example has two -conversions: `Rc` to `String` and then `String` to `&str`. Rust will do +conversions: `&Rc` to `&String` and then `&String` to `&str`. Rust will do this as many times as possible until the types match. Another very common implementation provided by the standard library is: diff --git a/src/doc/book/getting-started.md b/src/doc/book/getting-started.md index bff448aadd..203dbf16ca 100644 --- a/src/doc/book/getting-started.md +++ b/src/doc/book/getting-started.md @@ -111,41 +111,40 @@ unofficial locations. Note that this table can be expanded over time, this isn't the exhaustive set of tier 3 platforms that will ever be! -## Installing on Linux or Mac +## Installing Rust -If we're on Linux or a Mac, all we need to do is open a terminal and type this: +All you need to do on Unix systems like Linux and macOS is open a +terminal and type this: ```bash -$ curl -sSf https://static.rust-lang.org/rustup.sh | sh +$ curl https://sh.rustup.rs -sSf | sh ``` -This will download a script, and start the installation. If it all goes well, -you’ll see this appear: +It will download a script, and start the installation. If everything +goes well, you’ll see this appear: ```text -Rust is ready to roll. +Rust is installed now. Great! ``` -From here, press `y` for ‘yes’, and then follow the rest of the prompts. +Installing on Windows is nearly as easy: download and run +[rustup-init.exe]. It will start the installation in a console and +present the above message on success. -## Installing on Windows +For other installation options and information, visit the [install] +page of the Rust website. -If you're on Windows, please download the appropriate [installer][install-page]. - -[install-page]: https://www.rust-lang.org/install.html +[rustup-init.exe]: https://win.rustup.rs +[install]: https://www.rust-lang.org/install.html ## Uninstalling -Uninstalling Rust is as easy as installing it. On Linux or Mac, run -the uninstall script: +Uninstalling Rust is as easy as installing it: ```bash -$ sudo /usr/local/lib/rustlib/uninstall.sh +$ rustup self uninstall ``` -If we used the Windows installer, we can re-run the `.msi` and it will give us -an uninstall option. - ## Troubleshooting If we've got Rust installed, we can open up a shell, and type this: @@ -158,20 +157,33 @@ You should see the version number, commit hash, and commit date. If you do, Rust has been installed successfully! Congrats! -If you don't and you're on Windows, check that Rust is in your %PATH% system -variable: `$ echo %PATH%`. If it isn't, run the installer again, select "Change" -on the "Change, repair, or remove installation" page and ensure "Add to PATH" is -installed on the local hard drive. If you need to configure your path manually, -you can find the Rust executables in a directory like -`"C:\Program Files\Rust stable GNU 1.x\bin"`. +If you don't, that probably means that the `PATH` environment variable +doesn't include Cargo's binary directory, `~/.cargo/bin` on Unix, or +`%USERPROFILE%\.cargo\bin` on Windows. This is the directory where +Rust development tools live, and most Rust developers keep it in their +`PATH` environment variable, which makes it possible to run `rustc` on +the command line. Due to differences in operating systems, command +shells, and bugs in installation, you may need to restart your shell, +log out of the system, or configure `PATH` manually as appropriate for +your operating environment. Rust does not do its own linking, and so you’ll need to have a linker -installed. Doing so will depend on your specific system, consult its -documentation for more details. - -If not, there are a number of places where we can get help. The easiest is -[the #rust-beginners IRC channel on irc.mozilla.org][irc-beginners] and for -general discussion [the #rust IRC channel on irc.mozilla.org][irc], which we +installed. Doing so will depend on your specific system. For +Linux-based systems, Rust will attempt to call `cc` for linking. On +`windows-msvc` (Rust built on Windows with Microsoft Visual Studio), +this depends on having [Microsoft Visual C++ Build Tools][msvbt] +installed. These do not need to be in `%PATH%` as `rustc` will find +them automatically. In general, if you have your linker in a +non-traditional location you can call `rustc +linker=/path/to/cc`, where `/path/to/cc` should point to your linker path. + +[msvbt]: http://landinghub.visualstudio.com/visual-cpp-build-tools + +If you are still stuck, there are a number of places where we can get +help. The easiest is +[the #rust-beginners IRC channel on irc.mozilla.org][irc-beginners] +and for general discussion +[the #rust IRC channel on irc.mozilla.org][irc], which we can access through [Mibbit][mibbit]. Then we'll be chatting with other Rustaceans (a silly nickname we call ourselves) who can help us out. Other great resources include [the user’s forum][users] and [Stack Overflow][stackoverflow]. @@ -183,9 +195,7 @@ resources include [the user’s forum][users] and [Stack Overflow][stackoverflow [stackoverflow]: http://stackoverflow.com/questions/tagged/rust This installer also installs a copy of the documentation locally, so we 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 the directory to which Rust -was installed. +read it offline. It's only a `rustup doc` away! # Hello, world! @@ -495,6 +505,9 @@ $ cargo run Hello, world! ``` +The `run` command comes in handy when you need to rapidly iterate on a +project. + Notice that this example didn’t re-build the project. Cargo figured out that the file hasn’t changed, and so it just ran the binary. If you'd modified your source code, Cargo would have rebuilt the project before running it, and you diff --git a/src/doc/book/guessing-game.md b/src/doc/book/guessing-game.md index 22cf6068e4..a3ab4803bc 100644 --- a/src/doc/book/guessing-game.md +++ b/src/doc/book/guessing-game.md @@ -56,9 +56,7 @@ $ cargo build Excellent! Open up your `src/main.rs` again. We’ll be writing all of our code in this file. -Before we move on, let me show you one more Cargo command: `run`. `cargo run` -is kind of like `cargo build`, but it also then runs the produced executable. -Try it out: +Remember the `run` command from last chapter? Try it out again here: ```bash $ cargo run @@ -67,9 +65,8 @@ $ cargo run Hello, world! ``` -Great! The `run` command comes in handy when you need to rapidly iterate on a -project. Our game is such a project, we need to quickly test each -iteration before moving on to the next one. +Great! Our game is just the kind of project `run` is good for: we need +to quickly test each iteration before moving on to the next one. # Processing a Guess @@ -279,7 +276,7 @@ displaying the message. [expect]: ../std/result/enum.Result.html#method.expect [panic]: error-handling.html -If we leave off calling this method, our program will compile, but +If we do not call `expect()`, our program will compile, but we’ll get a warning: ```bash @@ -365,7 +362,6 @@ numbers. A bare number like above is actually shorthand for `^0.3.0`, meaning "anything compatible with 0.3.0". If we wanted to use only `0.3.0` exactly, we could say `rand="=0.3.0"` (note the two equal signs). -And if we wanted to use the latest version we could use `rand="*"`. We could also use a range of versions. [Cargo’s documentation][cargodoc] contains more details. diff --git a/src/doc/book/lifetimes.md b/src/doc/book/lifetimes.md index f7d9c94bc4..df1ee5a293 100644 --- a/src/doc/book/lifetimes.md +++ b/src/doc/book/lifetimes.md @@ -50,29 +50,94 @@ complicated. For example, imagine this set of operations: 4. You decide to use the resource. Uh oh! Your reference is pointing to an invalid resource. This is called a -dangling pointer or ‘use after free’, when the resource is memory. +dangling pointer or ‘use after free’, when the resource is memory. A small +example of such a situation would be: + +```rust,compile_fail +let r; // Introduce reference: r +{ + let i = 1; // Introduce scoped value: i + r = &i; // Store reference of i in r +} // i goes out of scope and is dropped. + +println!("{}", r); // r still refers to i +``` To fix this, we have to make sure that step four never happens after step -three. The ownership system in Rust does this through a concept called -lifetimes, which describe the scope that a reference is valid for. +three. In the small example above the Rust compiler is able to report the issue +as it can see the lifetimes of the various values in the function. -When we have a function that takes an argument by reference, we can be -implicit or explicit about the lifetime of the reference: +When we have a function that takes arguments by reference the situation becomes +more complex. Consider the following example: -```rust -// implicit -fn foo(x: &i32) { +```rust,compile_fail,E0106 +fn skip_prefix(line: &str, prefix: &str) -> &str { + // ... +# line } -// explicit -fn bar<'a>(x: &'a i32) { +let line = "lang:en=Hello World!"; +let lang = "en"; + +let v; +{ + let p = format!("lang:{}=", lang); // -+ p goes into scope + v = skip_prefix(line, p.as_str()); // | +} // -+ p goes out of scope +println!("{}", v); +``` + +Here we have a function `skip_prefix` which takes two `&str` references +as parameters and returns a single `&str` reference. We call it +by passing in references to `line` and `p`: Two variables with different +lifetimes. Now the safety of the `println!`-line depends on whether the +reference returned by `skip_prefix` function references the still living +`line` or the already dropped `p` string. + +Because of the above ambiguity, Rust will refuse to compile the example +code. To get it to compile we need to tell the compiler more about the +lifetimes of the references. This can be done by making the lifetimes +explicit in the function declaration: + +```rust +fn skip_prefix<'a, 'b>(line: &'a str, prefix: &'b str) -> &'a str { + // ... +# line } ``` +Let's examine the changes without going too deep into the syntax for now - +we'll get to that later. The first change was adding the `<'a, 'b>` after the +method name. This introduces two lifetime parameters: `'a` and `'b`. Next each +reference in the function signature was associated with one of the lifetime +parameters by adding the lifetime name after the `&`. This tells the compiler +how the lifetimes between different references are related. + +As a result the compiler is now able to deduce that the return value of +`skip_prefix` has the same lifetime as the `line` parameter, which makes the `v` +reference safe to use even after the `p` goes out of scope in the original +example. + +In addition to the compiler being able to validate the usage of `skip_prefix` +return value, it can also ensure that the implementation follows the contract +established by the function declaration. This is useful especially when you are +implementing traits that are introduced [later in the book][traits]. + +**Note** It's important to understand that lifetime annotations are +_descriptive_, not _prescriptive_. This means that how long a reference is valid +is determined by the code, not by the annotations. The annotations, however, +give information about lifetimes to the compiler that uses them to check the +validity of references. The compiler can do so without annotations in simple +cases, but needs the programmers support in complex scenarios. + +[traits]: traits.html + +# Syntax + The `'a` reads ‘the lifetime a’. Technically, every reference has some lifetime associated with it, but the compiler lets you elide (i.e. omit, see -["Lifetime Elision"][lifetime-elision] below) them in common cases. -Before we get to that, though, let’s break the explicit example down: +["Lifetime Elision"][lifetime-elision] below) them in common cases. Before we +get to that, though, let’s look at a short example with explicit lifetimes: [lifetime-elision]: #lifetime-elision @@ -90,7 +155,8 @@ focus on the lifetimes aspect. [generics]: generics.html We use `<>` to declare our lifetimes. This says that `bar` has one lifetime, -`'a`. If we had two reference parameters, it would look like this: +`'a`. If we had two reference parameters with different lifetimes, it would +look like this: ```rust,ignore diff --git a/src/doc/book/references-and-borrowing.md b/src/doc/book/references-and-borrowing.md index 2ec3a00c0d..1e2f061b06 100644 --- a/src/doc/book/references-and-borrowing.md +++ b/src/doc/book/references-and-borrowing.md @@ -86,7 +86,7 @@ fn main() { return v.iter().fold(0, |a, &b| a + b); } // Borrow two vectors and sum them. - // This kind of borrowing does not allow mutation to the borrowed. + // This kind of borrowing does not allow mutation through the borrowed reference. fn foo(v1: &Vec, v2: &Vec) -> i32 { // do stuff with v1 and v2 let s1 = sum_vec(v1); @@ -240,7 +240,7 @@ fn main() { In other words, the mutable borrow is held through the rest of our example. What we want is for the mutable borrow by `y` to end so that the resource can be -returned to the owner, `x`. `x` can then provide a immutable borrow to `println!`. +returned to the owner, `x`. `x` can then provide an immutable borrow to `println!`. In Rust, borrowing is tied to the scope that the borrow is valid for. And our scopes look like this: diff --git a/src/doc/book/syntax-index.md b/src/doc/book/syntax-index.md index 0259db221b..28403711cd 100644 --- a/src/doc/book/syntax-index.md +++ b/src/doc/book/syntax-index.md @@ -61,7 +61,6 @@ * `-` (`- expr`): arithmetic negation. Overloadable (`Neg`). * `-=` (`var -= expr`): arithmetic subtraction & assignment. Overloadable (`SubAssign`). * `->` (`fn(…) -> type`, `|…| -> type`): function and closure return type. See [Functions], [Closures]. -* `-> !` (`fn(…) -> !`, `|…| -> !`): diverging function or closure. See [Diverging Functions]. * `.` (`expr.ident`): member access. See [Structs], [Method Syntax]. * `..` (`..`, `expr..`, `..expr`, `expr..expr`): right-exclusive range literal. * `..` (`..expr`): struct literal update syntax. See [Structs (Update syntax)]. @@ -95,6 +94,7 @@ * `|=` (`var |= expr`): bitwise or & assignment. Overloadable (`BitOrAssign`). * `||` (`expr || expr`): logical or. * `_`: "ignored" pattern binding (see [Patterns (Ignoring bindings)]). Also used to make integer-literals readable (see [Reference (Integer literals)]). +* `?` (`expr?`): Error propagation. Returns early when `Err(_)` is encountered, unwraps otherwise. Similar to the [`try!` macro]. ## Other Syntax @@ -159,6 +159,10 @@ * `/*!…*/`: inner block doc comment. See [Comments]. * `/**…*/`: outer block doc comment. See [Comments]. + + +* `!`: always empty Never type. See [Diverging Functions]. + * `()`: empty tuple (*a.k.a.* unit), both literal and type. @@ -207,6 +211,7 @@ [Functions]: functions.html [Generics]: generics.html [Iterators]: iterators.html +[`try!` macro]: error-handling.html#the-try-macro [Lifetimes]: lifetimes.html [Loops (`for`)]: loops.html#for [Loops (`loop`)]: loops.html#loop diff --git a/src/doc/book/testing.md b/src/doc/book/testing.md index 86729147ed..0e6cdb8f09 100644 --- a/src/doc/book/testing.md +++ b/src/doc/book/testing.md @@ -24,9 +24,11 @@ Cargo will automatically generate a simple test when you make a new project. Here's the contents of `src/lib.rs`: ```rust -# fn main() {} -#[test] -fn it_works() { +#[cfg(test)] +mod tests { + #[test] + fn it_works() { + } } ``` @@ -36,11 +38,11 @@ currently has no body. That's good enough to pass! We can run the tests with ```bash $ cargo test - Compiling adder v0.0.1 (file:///home/you/projects/adder) - Running target/adder-91b3e234d4ed382a + Compiling adder v0.1.0 (file:///home/you/projects/adder) + Running target/debug/deps/adder-91b3e234d4ed382a running 1 test -test it_works ... ok +test tests::it_works ... ok test result: ok. 1 passed; 0 failed; 0 ignored; 0 measured @@ -56,7 +58,7 @@ for the test we wrote, and another for documentation tests. We'll talk about those later. For now, see this line: ```text -test it_works ... ok +test tests::it_works ... ok ``` Note the `it_works`. This comes from the name of our function: @@ -89,31 +91,30 @@ run our tests again: ```bash $ cargo test - Compiling adder v0.0.1 (file:///home/you/projects/adder) - Running target/adder-91b3e234d4ed382a + Compiling adder v0.1.0 (file:///home/you/projects/adder) + Running target/debug/deps/adder-91b3e234d4ed382a running 1 test -test it_works ... FAILED +test tests::it_works ... FAILED failures: ----- it_works stdout ---- - thread 'it_works' panicked at 'assertion failed: false', /home/steve/tmp/adder/src/lib.rs:3 - +---- test::it_works stdout ---- + thread 'tests::it_works' panicked at 'assertion failed: false', src/lib.rs:5 failures: - it_works + tests::it_works test result: FAILED. 0 passed; 1 failed; 0 ignored; 0 measured -thread 'main' panicked at 'Some tests failed', /home/steve/src/rust/src/libtest/lib.rs:247 +error: test failed ``` Rust indicates that our test failed: ```text -test it_works ... FAILED +test tests::it_works ... FAILED ``` And that's reflected in the summary line: @@ -159,11 +160,11 @@ This test will now succeed if we `panic!` and fail if we complete. Let's try it: ```bash $ cargo test - Compiling adder v0.0.1 (file:///home/you/projects/adder) - Running target/adder-91b3e234d4ed382a + Compiling adder v0.1.0 (file:///home/you/projects/adder) + Running target/debug/deps/adder-91b3e234d4ed382a running 1 test -test it_works ... ok +test tests::it_works ... ok test result: ok. 1 passed; 0 failed; 0 ignored; 0 measured @@ -191,11 +192,11 @@ passes: ```bash $ cargo test - Compiling adder v0.0.1 (file:///home/you/projects/adder) - Running target/adder-91b3e234d4ed382a + Compiling adder v0.1.0 (file:///home/you/projects/adder) + Running target/debug/deps/adder-91b3e234d4ed382a running 1 test -test it_works ... ok +test tests::it_works ... ok test result: ok. 1 passed; 0 failed; 0 ignored; 0 measured @@ -262,8 +263,8 @@ not: ```bash $ cargo test - Compiling adder v0.0.1 (file:///home/you/projects/adder) - Running target/adder-91b3e234d4ed382a + Compiling adder v0.1.0 (file:///home/you/projects/adder) + Running target/debug/deps/adder-91b3e234d4ed382a running 2 tests test expensive_test ... ignored @@ -282,7 +283,7 @@ The expensive tests can be run explicitly using `cargo test -- --ignored`: ```bash $ cargo test -- --ignored - Running target/adder-91b3e234d4ed382a + Running target/debug/deps/adder-91b3e234d4ed382a running 1 test test expensive_test ... ok @@ -302,8 +303,11 @@ which is why the command is `cargo test -- --ignored`. # The `tests` module There is one way in which our existing example is not idiomatic: it's -missing the `tests` module. The idiomatic way of writing our example -looks like this: +missing the `tests` module. You might have noticed this test module was +present in the code that was initially generated with `cargo new` but +was missing from our last example. Let's explain what this does. + +The idiomatic way of writing our example looks like this: ```rust,ignore # fn main() {} @@ -356,8 +360,8 @@ Note the different `use` line. Now we run our tests: ```bash $ cargo test Updating registry `https://github.com/rust-lang/crates.io-index` - Compiling adder v0.0.1 (file:///home/you/projects/adder) - Running target/adder-91b3e234d4ed382a + Compiling adder v0.1.0 (file:///home/you/projects/adder) + Running target/debug/deps/adder-91b3e234d4ed382a running 1 test test tests::it_works ... ok @@ -380,9 +384,9 @@ the `tests` directory. # The `tests` directory -Each file in `tests/*.rs` directory is treated as individual crate. -So, to write an integration test, let's make a `tests` directory, and -put a `tests/integration_test.rs` file inside, with this as its contents: +Each file in `tests/*.rs` directory is treated as an individual crate. +To write an integration test, let's make a `tests` directory and +put a `tests/integration_test.rs` file inside with this as its contents: ```rust,ignore extern crate adder; @@ -404,15 +408,15 @@ Let's run them: ```bash $ cargo test - Compiling adder v0.0.1 (file:///home/you/projects/adder) - Running target/adder-91b3e234d4ed382a + Compiling adder v0.1.0 (file:///home/you/projects/adder) + Running target/debug/deps/adder-91b3e234d4ed382a running 1 test test tests::it_works ... ok test result: ok. 1 passed; 0 failed; 0 ignored; 0 measured - Running target/lib-c18e7d3494509e74 + Running target/debug/integration_test-68064b69521c828a running 1 test test it_works ... ok @@ -490,15 +494,15 @@ Let's run the tests again: ```bash $ cargo test - Compiling adder v0.0.1 (file:///home/steve/tmp/adder) - Running target/adder-91b3e234d4ed382a + Compiling adder v0.1.0. (file:///home/you/projects/adder) + Running target/debug/deps/adder-91b3e234d4ed382a running 1 test test tests::it_works ... ok test result: ok. 1 passed; 0 failed; 0 ignored; 0 measured - Running target/lib-c18e7d3494509e74 + Running target/debug/integration_test-68064b69521c828a running 1 test test it_works ... ok diff --git a/src/doc/book/type-aliases.md b/src/doc/book/type-aliases.md index def2e31f35..3798336f0a 100644 --- a/src/doc/book/type-aliases.md +++ b/src/doc/book/type-aliases.md @@ -1,4 +1,4 @@ -% `type` Aliases +% Type Aliases The `type` keyword lets you declare an alias of another type: diff --git a/src/doc/book/variable-bindings.md b/src/doc/book/variable-bindings.md index 30e922d7f4..03f17371de 100644 --- a/src/doc/book/variable-bindings.md +++ b/src/doc/book/variable-bindings.md @@ -161,7 +161,7 @@ Could not compile `hello_world`. Rust will not let us use a value that has not been initialized. -Let take a minute to talk about this stuff we've added to `println!`. +Let us take a minute to 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 diff --git a/src/doc/footer.inc b/src/doc/footer.inc index 7513e524e7..77e151235e 100644 --- a/src/doc/footer.inc +++ b/src/doc/footer.inc @@ -5,4 +5,3 @@ or the MIT license, at your op

This file may not be copied, modified, or distributed except according to those terms.

- diff --git a/src/doc/grammar.md b/src/doc/grammar.md index be64379b51..690d44cc2c 100644 --- a/src/doc/grammar.md +++ b/src/doc/grammar.md @@ -764,6 +764,13 @@ bound-list := bound | bound '+' bound-list bound := path | lifetime ``` +### Never type +An empty type + +```antlr +never_type : "!" ; +``` + ### Object types **FIXME:** grammar? diff --git a/src/doc/reference.md b/src/doc/reference.md index 9f4830cd19..711a13d21f 100644 --- a/src/doc/reference.md +++ b/src/doc/reference.md @@ -2479,8 +2479,6 @@ The currently implemented features of the reference compiler are: * - `abi_vectorcall` - Allows the usage of the vectorcall calling convention (e.g. `extern "vectorcall" func fn_();`) -* - `dotdot_in_tuple_patterns` - Allows `..` in tuple (struct) patterns. - * - `abi_sysv64` - Allows the usage of the system V AMD64 calling convention (e.g. `extern "sysv64" func fn_();`) @@ -2860,8 +2858,8 @@ assert_eq!(x, y); ### Unary operator expressions -Rust defines the following unary operators. They are all written as prefix operators, -before the expression they apply to. +Rust defines the following unary operators. With the exception of `?`, they are +all written as prefix operators, before the expression they apply to. * `-` : Negation. Signed integer types and floating-point types support negation. It @@ -2890,6 +2888,10 @@ before the expression they apply to. If the `&` or `&mut` operators are applied to an rvalue, a temporary value is created; the lifetime of this temporary value is defined by [syntactic rules](#temporary-lifetimes). +* `?` + : Propagating errors if applied to `Err(_)` and unwrapping if + applied to `Ok(_)`. Only works on the `Result` type, + and written in postfix notation. ### Binary operator expressions @@ -3109,10 +3111,12 @@ the lambda expression captures its environment by reference, effectively borrowing pointers to all outer variables mentioned inside the function. Alternately, the compiler may infer that a lambda expression should copy or move values (depending on their type) from the environment into the lambda -expression's captured environment. +expression's captured environment. A lambda can be forced to capture its +environment by moving values by prefixing it with the `move` keyword. In this example, we define a function `ten_times` that takes a higher-order -function argument, and we then call it with a lambda expression as an argument: +function argument, and we then call it with a lambda expression as an argument, +followed by a lambda expression that moves values from its environment. ``` fn ten_times(f: F) where F: Fn(i32) { @@ -3122,6 +3126,9 @@ fn ten_times(f: F) where F: Fn(i32) { } ten_times(|j| println!("hello, {}", j)); + +let word = "konnichiwa".to_owned(); +ten_times(move |j| println!("{}, {}", word, j)); ``` ### Infinite loops @@ -3750,6 +3757,21 @@ The special type `Self` has a meaning within traits and impls. In a trait defini to an implicit type parameter representing the "implementing" type. In an impl, it is an alias for the implementing type. For example, in: +``` +pub trait From { + fn from(T) -> Self; +} + +impl From for String { + fn from(x: i32) -> Self { + x.to_string() + } +} +``` + +The notation `Self` in the impl refers to the implementing type: `String`. In another +example: + ``` trait Printable { fn make_string(&self) -> String; @@ -3958,6 +3980,16 @@ the top-level type for the implementation of the called method. If no such metho found, `.deref()` is called and the compiler continues to search for the method implementation in the returned type `U`. +## The `Send` trait + +The `Send` trait indicates that a value of this type is safe to send from one +thread to another. + +## The `Sync` trait + +The `Sync` trait indicates that a value of this type is safe to share between +multiple threads. + # Memory model A Rust program's memory consists of a static set of *items* and a *heap*. @@ -4008,9 +4040,9 @@ Methods that take either `self` or `Box` can optionally place them in a mutable variable by prefixing them with `mut` (similar to regular arguments): ``` -trait Changer { - fn change(mut self) -> Self; - fn modify(mut self: Box) -> Box; +trait Changer: Sized { + fn change(mut self) {} + fn modify(mut self: Box) {} } ``` @@ -4063,6 +4095,12 @@ be ignored in favor of only building the artifacts specified by command line. Rust code into an existing non-Rust application because it will not have dynamic dependencies on other Rust code. +* `--crate-type=cdylib`, `#[crate_type = "cdylib"]` - A dynamic system + library will be produced. This is used when compiling Rust code as + a dynamic library to be loaded from another language. This output type will + create `*.so` files on Linux, `*.dylib` files on OSX, and `*.dll` files on + Windows. + * `--crate-type=rlib`, `#[crate_type = "rlib"]` - A "Rust library" file will be produced. This is used as an intermediate artifact and can be thought of as a "static Rust library". These `rlib` files, unlike `staticlib` files, are diff --git a/src/doc/rust.css b/src/doc/rust.css index 262db5673e..932594b991 100644 --- a/src/doc/rust.css +++ b/src/doc/rust.css @@ -336,13 +336,11 @@ table th { /* Code snippets */ -.rusttest { display: none; } pre.rust { position: relative; } a.test-arrow { + background-color: rgba(78, 139, 202, 0.2); display: inline-block; position: absolute; - - background-color: #4e8bca; color: #f5f5f5; padding: 5px 10px 5px 10px; border-radius: 5px; @@ -350,6 +348,10 @@ a.test-arrow { top: 5px; right: 5px; } +a.test-arrow:hover{ + background-color: #4e8bca; + text-decoration: none; +} .unstable-feature { border: 2px solid red; diff --git a/src/etc/local_stage0.sh b/src/etc/local_stage0.sh index 645a80ab8b..ee77206640 100755 --- a/src/etc/local_stage0.sh +++ b/src/etc/local_stage0.sh @@ -71,6 +71,7 @@ cp ${PREFIX}/${LIB_DIR}/${LIB_PREFIX}log*${LIB_SUF} ${TARG_DIR}/stage0/${LIB_DIR cp ${PREFIX}/${LIB_DIR}/${LIB_PREFIX}rbml*${LIB_SUF} ${TARG_DIR}/stage0/${LIB_DIR}/ cp ${PREFIX}/${LIB_DIR}/${LIB_PREFIX}serialize*${LIB_SUF} ${TARG_DIR}/stage0/${LIB_DIR}/ cp ${PREFIX}/${LIB_DIR}/${LIB_PREFIX}term*${LIB_SUF} ${TARG_DIR}/stage0/${LIB_DIR}/ +cp ${PREFIX}/${LIB_DIR}/${LIB_PREFIX}proc_macro*${LIB_SUF} ${TARG_DIR}/stage0/${LIB_DIR}/ # do not fail if one of the above fails, as all we need is a working rustc! exit 0 diff --git a/src/liballoc/arc.rs b/src/liballoc/arc.rs index 5f9ccd1820..d6096d5894 100644 --- a/src/liballoc/arc.rs +++ b/src/liballoc/arc.rs @@ -10,35 +10,11 @@ #![stable(feature = "rust1", since = "1.0.0")] -//! Threadsafe reference-counted boxes (the `Arc` type). +//! Thread-safe reference-counting pointers. //! -//! The `Arc` type provides shared ownership of an immutable value through -//! atomic reference counting. +//! See the [`Arc`][arc] documentation for more details. //! -//! `Weak` is a weak reference to the `Arc` box, and it is created by -//! the `downgrade` method. -//! # Examples -//! -//! Sharing some immutable data between threads: -//! -// Note that we **do not** run these tests here. The windows builders get super -// unhappy of a thread outlives the main thread and then exits at the same time -// (something deadlocks) so we just avoid this entirely by not running these -// tests. -//! ```no_run -//! use std::sync::Arc; -//! use std::thread; -//! -//! let five = Arc::new(5); -//! -//! for _ in 0..10 { -//! let five = five.clone(); -//! -//! thread::spawn(move || { -//! println!("{:?}", five); -//! }); -//! } -//! ``` +//! [arc]: struct.Arc.html use boxed::Box; @@ -60,74 +36,120 @@ use core::{isize, usize}; use core::convert::From; use heap::deallocate; +/// A soft limit on the amount of references that may be made to an `Arc`. +/// +/// Going above this limit will abort your program (although not +/// necessarily) at _exactly_ `MAX_REFCOUNT + 1` references. const MAX_REFCOUNT: usize = (isize::MAX) as usize; -/// An atomically reference counted wrapper for shared state. -/// Destruction is deterministic, and will occur as soon as the last owner is -/// gone. It is marked as `Send` because it uses atomic reference counting. +/// A thread-safe reference-counting pointer. /// -/// If you do not need thread-safety, and just need shared ownership, consider -/// the [`Rc` type](../rc/struct.Rc.html). It is the same as `Arc`, but -/// does not use atomics, making it both thread-unsafe as well as significantly -/// faster when updating the reference count. +/// The type `Arc` provides shared ownership of a value of type `T`, +/// allocated in the heap. Invoking [`clone`][clone] on `Arc` produces +/// a new pointer to the same value in the heap. When the last `Arc` +/// pointer to a given value is destroyed, the pointed-to value is +/// also destroyed. /// -/// Note: the inherent methods defined on `Arc` are all associated functions, -/// which means that you have to call them as e.g. `Arc::get_mut(&value)` -/// instead of `value.get_mut()`. This is so that there are no conflicts with -/// methods on the inner type `T`, which are what you want to call in the -/// majority of cases. +/// Shared references in Rust disallow mutation by default, and `Arc` is no +/// exception. If you need to mutate through an `Arc`, use [`Mutex`][mutex], +/// [`RwLock`][rwlock], or one of the [`Atomic`][atomic] types. /// -/// # Examples +/// `Arc` uses atomic operations for reference counting, so `Arc`s can be +/// sent between threads. In other words, `Arc` implements [`Send`][send] +/// as long as `T` implements `Send` and [`Sync`][sync]. The disadvantage is +/// that atomic operations are more expensive than ordinary memory accesses. +/// If you are not sharing reference-counted values between threads, consider +/// using [`rc::Rc`][rc] for lower overhead. `Rc` is a safe default, because +/// the compiler will catch any attempt to send an `Rc` between threads. +/// However, a library might choose `Arc` in order to give library consumers +/// more flexibility. /// -/// In this example, a large vector of data will be shared by several threads. First we -/// wrap it with a `Arc::new` and then clone the `Arc` reference for every thread (which will -/// increase the reference count atomically). +/// The [`downgrade`][downgrade] method can be used to create a non-owning +/// [`Weak`][weak] pointer. A `Weak` pointer can be [`upgrade`][upgrade]d +/// to an `Arc`, but this will return [`None`][option] if the value has +/// already been dropped. +/// +/// A cycle between `Arc` pointers will never be deallocated. For this reason, +/// `Weak` is used to break cycles. For example, a tree could have strong +/// `Arc` pointers from parent nodes to children, and `Weak` pointers from +/// children back to their parents. +/// +/// `Arc` automatically dereferences to `T` (via the [`Deref`][deref] trait), +/// so you can call `T`'s methods on a value of type `Arc`. To avoid name +/// clashes with `T`'s methods, the methods of `Arc` itself are [associated +/// functions][assoc], called using function-like syntax: /// /// ``` /// use std::sync::Arc; -/// use std::thread; +/// let my_arc = Arc::new(()); /// -/// fn main() { -/// let numbers: Vec<_> = (0..100).collect(); -/// let shared_numbers = Arc::new(numbers); +/// Arc::downgrade(&my_arc); +/// ``` /// -/// for _ in 0..10 { -/// // prepare a copy of reference here and it will be moved to the thread -/// let child_numbers = shared_numbers.clone(); +/// `Weak` does not auto-dereference to `T`, because the value may have +/// already been destroyed. /// -/// thread::spawn(move || { -/// let local_numbers = &child_numbers[..]; +/// [arc]: struct.Arc.html +/// [weak]: struct.Weak.html +/// [rc]: ../../std/rc/struct.Rc.html +/// [clone]: ../../std/clone/trait.Clone.html#tymethod.clone +/// [mutex]: ../../std/sync/struct.Mutex.html +/// [rwlock]: ../../std/sync/struct.RwLock.html +/// [atomic]: ../../std/sync/atomic/index.html +/// [send]: ../../std/marker/trait.Send.html +/// [sync]: ../../std/marker/trait.Sync.html +/// [deref]: ../../std/ops/trait.Deref.html +/// [downgrade]: struct.Arc.html#method.downgrade +/// [upgrade]: struct.Weak.html#method.upgrade +/// [option]: ../../std/option/enum.Option.html +/// [assoc]: ../../book/method-syntax.html#associated-functions /// -/// // Work with the local numbers -/// }); -/// } -/// } -/// ``` -/// You can also share mutable data between threads safely -/// by putting it inside `Mutex` and then share `Mutex` immutably -/// with `Arc` as shown below. +/// # Examples /// -// See comment at the top of this file for why the test is no_run +/// Sharing some immutable data between threads: +/// +// Note that we **do not** run these tests here. The windows builders get super +// unhappy if a thread outlives the main thread and then exits at the same time +// (something deadlocks) so we just avoid this entirely by not running these +// tests. /// ```no_run -/// use std::sync::{Arc, Mutex}; +/// use std::sync::Arc; /// use std::thread; /// -/// let five = Arc::new(Mutex::new(5)); +/// let five = Arc::new(5); /// /// for _ in 0..10 { /// let five = five.clone(); /// /// thread::spawn(move || { -/// let mut number = five.lock().unwrap(); +/// println!("{:?}", five); +/// }); +/// } +/// ``` /// -/// *number += 1; +/// Sharing a mutable `AtomicUsize`: /// -/// println!("{}", *number); // prints 6 +/// ```no_run +/// use std::sync::Arc; +/// use std::sync::atomic::{AtomicUsize, Ordering}; +/// use std::thread; +/// +/// let val = Arc::new(AtomicUsize::new(5)); +/// +/// for _ in 0..10 { +/// let val = val.clone(); +/// +/// thread::spawn(move || { +/// let v = val.fetch_add(1, Ordering::SeqCst); +/// println!("{:?}", v); /// }); /// } /// ``` - -#[cfg_attr(stage0, unsafe_no_drop_flag)] +/// +/// See the [`rc` documentation][rc_examples] for more examples of reference +/// counting in general. +/// +/// [rc_examples]: ../../std/rc/index.html#examples #[stable(feature = "rust1", since = "1.0.0")] pub struct Arc { ptr: Shared>, @@ -141,19 +163,18 @@ unsafe impl Sync for Arc {} #[unstable(feature = "coerce_unsized", issue = "27732")] impl, U: ?Sized> CoerceUnsized> for Arc {} -/// A weak pointer to an `Arc`. +/// A weak version of [`Arc`][arc]. /// -/// Weak pointers will not keep the data inside of the `Arc` alive, and can be -/// used to break cycles between `Arc` pointers. +/// `Weak` pointers do not count towards determining if the inner value +/// should be dropped. /// -/// A `Weak` pointer can be upgraded to an `Arc` pointer, but -/// will return `None` if the value has already been dropped. +/// The typical way to obtain a `Weak` pointer is to call +/// [`Arc::downgrade`][downgrade]. /// -/// For example, a tree with parent pointers can be represented by putting the -/// nodes behind strong `Arc` pointers, and then storing the parent pointers -/// as `Weak` pointers. - -#[cfg_attr(stage0, unsafe_no_drop_flag)] +/// See the [`Arc`][arc] documentation for more details. +/// +/// [arc]: struct.Arc.html +/// [downgrade]: struct.Arc.html#method.downgrade #[stable(feature = "arc_weak", since = "1.4.0")] pub struct Weak { ptr: Shared>, @@ -211,12 +232,15 @@ impl Arc { Arc { ptr: unsafe { Shared::new(Box::into_raw(x)) } } } - /// Unwraps the contained value if the `Arc` has exactly one strong reference. + /// Returns the contained value, if the `Arc` has exactly one strong reference. /// - /// Otherwise, an `Err` is returned with the same `Arc`. + /// Otherwise, an [`Err`][result] is returned with the same `Arc` that was + /// passed in. /// /// This will succeed even if there are outstanding weak references. /// + /// [result]: ../../std/result/enum.Result.html + /// /// # Examples /// /// ``` @@ -227,7 +251,7 @@ impl Arc { /// /// let x = Arc::new(4); /// let _y = x.clone(); - /// assert_eq!(Arc::try_unwrap(x), Err(Arc::new(4))); + /// assert_eq!(*Arc::try_unwrap(x).unwrap_err(), 4); /// ``` #[inline] #[stable(feature = "arc_unique", since = "1.4.0")] @@ -253,7 +277,9 @@ impl Arc { } impl Arc { - /// Downgrades the `Arc` to a `Weak` reference. + /// Creates a new [`Weak`][weak] pointer to this value. + /// + /// [weak]: struct.Weak.html /// /// # Examples /// @@ -291,7 +317,27 @@ impl Arc { } } - /// Get the number of weak references to this value. + /// Gets the number of [`Weak`][weak] pointers to this value. + /// + /// Be careful how you use this information, because another thread + /// may change the weak count at any time. + /// + /// [weak]: struct.Weak.html + /// + /// # Examples + /// + /// ``` + /// #![feature(arc_counts)] + /// + /// use std::sync::Arc; + /// + /// let five = Arc::new(5); + /// let _weak_five = Arc::downgrade(&five); + /// + /// // This assertion is deterministic because we haven't shared + /// // the `Arc` or `Weak` between threads. + /// assert_eq!(1, Arc::weak_count(&five)); + /// ``` #[inline] #[unstable(feature = "arc_counts", reason = "not clearly useful, and racy", issue = "28356")] @@ -299,7 +345,25 @@ impl Arc { this.inner().weak.load(SeqCst) - 1 } - /// Get the number of strong references to this value. + /// Gets the number of strong (`Arc`) pointers to this value. + /// + /// Be careful how you use this information, because another thread + /// may change the strong count at any time. + /// + /// # Examples + /// + /// ``` + /// #![feature(arc_counts)] + /// + /// use std::sync::Arc; + /// + /// let five = Arc::new(5); + /// let _also_five = five.clone(); + /// + /// // This assertion is deterministic because we haven't shared + /// // the `Arc` between threads. + /// assert_eq!(2, Arc::strong_count(&five)); + /// ``` #[inline] #[unstable(feature = "arc_counts", reason = "not clearly useful, and racy", issue = "28356")] @@ -336,8 +400,8 @@ impl Arc { #[unstable(feature = "ptr_eq", reason = "newly added", issue = "36497")] - /// Return whether two `Arc` references point to the same value - /// (not just values that compare equal). + /// Returns true if the two `Arc`s point to the same value (not + /// just values that compare as equal). /// /// # Examples /// @@ -362,9 +426,10 @@ impl Arc { #[stable(feature = "rust1", since = "1.0.0")] impl Clone for Arc { - /// Makes a clone of the `Arc`. + /// Makes a clone of the `Arc` pointer. /// - /// This increases the strong reference count. + /// This creates another pointer to the same inner value, increasing the + /// strong reference count. /// /// # Examples /// @@ -420,11 +485,17 @@ impl Deref for Arc { } impl Arc { - /// Make a mutable reference into the given `Arc`. - /// If the `Arc` has more than one strong reference, or any weak - /// references, the inner data is cloned. + /// Makes a mutable reference into the given `Arc`. + /// + /// If there are other `Arc` or [`Weak`][weak] pointers to the same value, + /// then `make_mut` will invoke [`clone`][clone] on the inner value to + /// ensure unique ownership. This is also referred to as clone-on-write. /// - /// This is also referred to as a copy-on-write. + /// See also [`get_mut`][get_mut], which will fail rather than cloning. + /// + /// [weak]: struct.Weak.html + /// [clone]: ../../std/clone/trait.Clone.html#tymethod.clone + /// [get_mut]: struct.Arc.html#method.get_mut /// /// # Examples /// @@ -439,10 +510,9 @@ impl Arc { /// *Arc::make_mut(&mut data) += 1; // Won't clone anything /// *Arc::make_mut(&mut other_data) *= 2; // Won't clone anything /// - /// // Note: data and other_data now point to different numbers + /// // Now `data` and `other_data` point to different values. /// assert_eq!(*data, 8); /// assert_eq!(*other_data, 12); - /// /// ``` #[inline] #[stable(feature = "arc_unique", since = "1.4.0")] @@ -501,8 +571,19 @@ impl Arc { } impl Arc { - /// Returns a mutable reference to the contained value if the `Arc` has - /// one strong reference and no weak references. + /// Returns a mutable reference to the inner value, if there are + /// no other `Arc` or [`Weak`][weak] pointers to the same value. + /// + /// Returns [`None`][option] otherwise, because it is not safe to + /// mutate a shared value. + /// + /// See also [`make_mut`][make_mut], which will [`clone`][clone] + /// the inner value when it's shared. + /// + /// [weak]: struct.Weak.html + /// [option]: ../../std/option/enum.Option.html + /// [make_mut]: struct.Arc.html#method.make_mut + /// [clone]: ../../std/clone/trait.Clone.html#tymethod.clone /// /// # Examples /// @@ -564,30 +645,32 @@ impl Arc { #[stable(feature = "rust1", since = "1.0.0")] impl Drop for Arc { - /// Drops the `Arc`. + /// Drops the `Arc`. /// /// This will decrement the strong reference count. If the strong reference - /// count becomes zero and the only other references are `Weak` ones, - /// `drop`s the inner value. + /// count reaches zero then the only other references (if any) are + /// [`Weak`][weak], so we `drop` the inner value. + /// + /// [weak]: struct.Weak.html /// /// # Examples /// /// ``` /// use std::sync::Arc; /// - /// { - /// let five = Arc::new(5); - /// - /// // stuff + /// struct Foo; /// - /// drop(five); // explicit drop + /// impl Drop for Foo { + /// fn drop(&mut self) { + /// println!("dropped!"); + /// } /// } - /// { - /// let five = Arc::new(5); /// - /// // stuff + /// let foo = Arc::new(Foo); + /// let foo2 = foo.clone(); /// - /// } // implicit drop + /// drop(foo); // Doesn't print anything + /// drop(foo2); // Prints "dropped!" /// ``` #[unsafe_destructor_blind_to_params] #[inline] @@ -625,10 +708,14 @@ impl Drop for Arc { } impl Weak { - /// Constructs a new `Weak` without an accompanying instance of T. + /// Constructs a new `Weak`, without an accompanying instance of `T`. /// - /// This allocates memory for T, but does not initialize it. Calling - /// Weak::upgrade() on the return value always gives None. + /// This allocates memory for `T`, but does not initialize it. Calling + /// [`upgrade`][upgrade] on the return value always gives + /// [`None`][option]. + /// + /// [upgrade]: struct.Weak.html#method.upgrade + /// [option]: ../../std/option/enum.Option.html /// /// # Examples /// @@ -636,6 +723,7 @@ impl Weak { /// use std::sync::Weak; /// /// let empty: Weak = Weak::new(); + /// assert!(empty.upgrade().is_none()); /// ``` #[stable(feature = "downgraded_weak", since = "1.10.0")] pub fn new() -> Weak { @@ -652,12 +740,13 @@ impl Weak { } impl Weak { - /// Upgrades a weak reference to a strong reference. + /// Upgrades the `Weak` pointer to an [`Arc`][arc], if possible. /// - /// Upgrades the `Weak` reference to an `Arc`, if possible. + /// Returns [`None`][option] if the strong count has reached zero and the + /// inner value was destroyed. /// - /// Returns `None` if there were no strong references and the data was - /// destroyed. + /// [arc]: struct.Arc.html + /// [option]: ../../std/option/enum.Option.html /// /// # Examples /// @@ -669,6 +758,13 @@ impl Weak { /// let weak_five = Arc::downgrade(&five); /// /// let strong_five: Option> = weak_five.upgrade(); + /// assert!(strong_five.is_some()); + /// + /// // Destroy all strong pointers. + /// drop(strong_five); + /// drop(five); + /// + /// assert!(weak_five.upgrade().is_none()); /// ``` #[stable(feature = "arc_weak", since = "1.4.0")] pub fn upgrade(&self) -> Option> { @@ -711,9 +807,10 @@ impl Weak { #[stable(feature = "arc_weak", since = "1.4.0")] impl Clone for Weak { - /// Makes a clone of the `Weak`. + /// Makes a clone of the `Weak` pointer. /// - /// This increases the weak reference count. + /// This creates another pointer to the same inner value, increasing the + /// weak reference count. /// /// # Examples /// @@ -745,7 +842,23 @@ impl Clone for Weak { #[stable(feature = "downgraded_weak", since = "1.10.0")] impl Default for Weak { - /// Constructs a new `Weak` without an accompanying instance of T. + /// Constructs a new `Weak`, without an accompanying instance of `T`. + /// + /// This allocates memory for `T`, but does not initialize it. Calling + /// [`upgrade`][upgrade] on the return value always gives + /// [`None`][option]. + /// + /// [upgrade]: struct.Weak.html#method.upgrade + /// [option]: ../../std/option/enum.Option.html + /// + /// # Examples + /// + /// ``` + /// use std::sync::Weak; + /// + /// let empty: Weak = Default::default(); + /// assert!(empty.upgrade().is_none()); + /// ``` fn default() -> Weak { Weak::new() } @@ -753,7 +866,7 @@ impl Default for Weak { #[stable(feature = "arc_weak", since = "1.4.0")] impl Drop for Weak { - /// Drops the `Weak`. + /// Drops the `Weak` pointer. /// /// This will decrement the weak reference count. /// @@ -762,21 +875,22 @@ impl Drop for Weak { /// ``` /// use std::sync::Arc; /// - /// { - /// let five = Arc::new(5); - /// let weak_five = Arc::downgrade(&five); - /// - /// // stuff + /// struct Foo; /// - /// drop(weak_five); // explicit drop + /// impl Drop for Foo { + /// fn drop(&mut self) { + /// println!("dropped!"); + /// } /// } - /// { - /// let five = Arc::new(5); - /// let weak_five = Arc::downgrade(&five); /// - /// // stuff + /// let foo = Arc::new(Foo); + /// let weak_foo = Arc::downgrade(&foo); + /// let other_weak_foo = weak_foo.clone(); /// - /// } // implicit drop + /// drop(weak_foo); // Doesn't print anything + /// drop(foo); // Prints "dropped!" + /// + /// assert!(other_weak_foo.upgrade().is_none()); /// ``` fn drop(&mut self) { let ptr = *self.ptr; @@ -798,9 +912,9 @@ impl Drop for Weak { #[stable(feature = "rust1", since = "1.0.0")] impl PartialEq for Arc { - /// Equality for two `Arc`s. + /// Equality for two `Arc`s. /// - /// Two `Arc`s are equal if their inner value are equal. + /// Two `Arc`s are equal if their inner values are equal. /// /// # Examples /// @@ -809,15 +923,15 @@ impl PartialEq for Arc { /// /// let five = Arc::new(5); /// - /// five == Arc::new(5); + /// assert!(five == Arc::new(5)); /// ``` fn eq(&self, other: &Arc) -> bool { *(*self) == *(*other) } - /// Inequality for two `Arc`s. + /// Inequality for two `Arc`s. /// - /// Two `Arc`s are unequal if their inner value are unequal. + /// Two `Arc`s are unequal if their inner values are unequal. /// /// # Examples /// @@ -826,7 +940,7 @@ impl PartialEq for Arc { /// /// let five = Arc::new(5); /// - /// five != Arc::new(5); + /// assert!(five != Arc::new(6)); /// ``` fn ne(&self, other: &Arc) -> bool { *(*self) != *(*other) @@ -834,7 +948,7 @@ impl PartialEq for Arc { } #[stable(feature = "rust1", since = "1.0.0")] impl PartialOrd for Arc { - /// Partial comparison for two `Arc`s. + /// Partial comparison for two `Arc`s. /// /// The two are compared by calling `partial_cmp()` on their inner values. /// @@ -842,16 +956,17 @@ impl PartialOrd for Arc { /// /// ``` /// use std::sync::Arc; + /// use std::cmp::Ordering; /// /// let five = Arc::new(5); /// - /// five.partial_cmp(&Arc::new(5)); + /// assert_eq!(Some(Ordering::Less), five.partial_cmp(&Arc::new(6))); /// ``` fn partial_cmp(&self, other: &Arc) -> Option { (**self).partial_cmp(&**other) } - /// Less-than comparison for two `Arc`s. + /// Less-than comparison for two `Arc`s. /// /// The two are compared by calling `<` on their inner values. /// @@ -862,13 +977,13 @@ impl PartialOrd for Arc { /// /// let five = Arc::new(5); /// - /// five < Arc::new(5); + /// assert!(five < Arc::new(6)); /// ``` fn lt(&self, other: &Arc) -> bool { *(*self) < *(*other) } - /// 'Less-than or equal to' comparison for two `Arc`s. + /// 'Less than or equal to' comparison for two `Arc`s. /// /// The two are compared by calling `<=` on their inner values. /// @@ -879,13 +994,13 @@ impl PartialOrd for Arc { /// /// let five = Arc::new(5); /// - /// five <= Arc::new(5); + /// assert!(five <= Arc::new(5)); /// ``` fn le(&self, other: &Arc) -> bool { *(*self) <= *(*other) } - /// Greater-than comparison for two `Arc`s. + /// Greater-than comparison for two `Arc`s. /// /// The two are compared by calling `>` on their inner values. /// @@ -896,13 +1011,13 @@ impl PartialOrd for Arc { /// /// let five = Arc::new(5); /// - /// five > Arc::new(5); + /// assert!(five > Arc::new(4)); /// ``` fn gt(&self, other: &Arc) -> bool { *(*self) > *(*other) } - /// 'Greater-than or equal to' comparison for two `Arc`s. + /// 'Greater than or equal to' comparison for two `Arc`s. /// /// The two are compared by calling `>=` on their inner values. /// @@ -913,7 +1028,7 @@ impl PartialOrd for Arc { /// /// let five = Arc::new(5); /// - /// five >= Arc::new(5); + /// assert!(five >= Arc::new(5)); /// ``` fn ge(&self, other: &Arc) -> bool { *(*self) >= *(*other) @@ -921,6 +1036,20 @@ impl PartialOrd for Arc { } #[stable(feature = "rust1", since = "1.0.0")] impl Ord for Arc { + /// Comparison for two `Arc`s. + /// + /// The two are compared by calling `cmp()` on their inner values. + /// + /// # Examples + /// + /// ``` + /// use std::sync::Arc; + /// use std::cmp::Ordering; + /// + /// let five = Arc::new(5); + /// + /// assert_eq!(Ordering::Less, five.cmp(&Arc::new(6))); + /// ``` fn cmp(&self, other: &Arc) -> Ordering { (**self).cmp(&**other) } @@ -951,7 +1080,16 @@ impl fmt::Pointer for Arc { #[stable(feature = "rust1", since = "1.0.0")] impl Default for Arc { - /// Creates a new `Arc`, with the `Default` value for T. + /// Creates a new `Arc`, with the `Default` value for `T`. + /// + /// # Examples + /// + /// ``` + /// use std::sync::Arc; + /// + /// let x: Arc = Default::default(); + /// assert_eq!(*x, 0); + /// ``` fn default() -> Arc { Arc::new(Default::default()) } @@ -1002,6 +1140,7 @@ mod tests { } #[test] + #[cfg_attr(target_os = "emscripten", ignore)] fn manually_share_arc() { let v = vec![1, 2, 3, 4, 5, 6, 7, 8, 9, 10]; let arc_v = Arc::new(v); diff --git a/src/liballoc/boxed.rs b/src/liballoc/boxed.rs index bc9b6e805e..28f4dda140 100644 --- a/src/liballoc/boxed.rs +++ b/src/liballoc/boxed.rs @@ -244,12 +244,14 @@ impl Box { /// the destructor of `T` and free the allocated memory. Since the /// way `Box` allocates and releases memory is unspecified, the /// only valid pointer to pass to this function is the one taken - /// from another `Box` via the `Box::into_raw` function. + /// from another `Box` via the [`Box::into_raw`] function. /// /// This function is unsafe because improper use may lead to /// memory problems. For example, a double-free may occur if the /// function is called twice on the same raw pointer. /// + /// [`Box::into_raw`]: struct.Box.html#method.into_raw + /// /// # Examples /// /// ``` @@ -269,12 +271,14 @@ impl Box { /// memory previously managed by the `Box`. In particular, the /// caller should properly destroy `T` and release the memory. The /// proper way to do so is to convert the raw pointer back into a - /// `Box` with the `Box::from_raw` function. + /// `Box` with the [`Box::from_raw`] function. /// /// Note: this is an associated function, which means that you have /// to call it as `Box::into_raw(b)` instead of `b.into_raw()`. This /// is so that there is no conflict with a method on the inner type. /// + /// [`Box::from_raw`]: struct.Box.html#method.from_raw + /// /// # Examples /// /// ``` diff --git a/src/liballoc/lib.rs b/src/liballoc/lib.rs index c6453da3f4..31491106d9 100644 --- a/src/liballoc/lib.rs +++ b/src/liballoc/lib.rs @@ -88,7 +88,6 @@ #![feature(staged_api)] #![feature(unboxed_closures)] #![feature(unique)] -#![cfg_attr(stage0, feature(unsafe_no_drop_flag))] #![feature(unsize)] #![cfg_attr(not(test), feature(fused, fn_traits, placement_new_protocol))] diff --git a/src/liballoc/raw_vec.rs b/src/liballoc/raw_vec.rs index 23542215fa..f23ea0ea8b 100644 --- a/src/liballoc/raw_vec.rs +++ b/src/liballoc/raw_vec.rs @@ -44,7 +44,6 @@ use core::cmp; /// `shrink_to_fit`, and `from_box` will actually set RawVec's private capacity /// field. This allows zero-sized types to not be special-cased by consumers of /// this type. -#[cfg_attr(stage0, unsafe_no_drop_flag)] pub struct RawVec { ptr: Unique, cap: usize, @@ -58,11 +57,7 @@ impl RawVec { pub fn new() -> Self { unsafe { // !0 is usize::MAX. This branch should be stripped at compile time. - let cap = if mem::size_of::() == 0 { - !0 - } else { - 0 - }; + let cap = if mem::size_of::() == 0 { !0 } else { 0 }; // heap::EMPTY doubles as "unallocated" and "zero-sized allocation" RawVec { @@ -210,11 +205,7 @@ impl RawVec { let (new_cap, ptr) = if self.cap == 0 { // skip to 4 because tiny Vec's are dumb; but not if that would cause overflow - let new_cap = if elem_size > (!0) / 8 { - 1 - } else { - 4 - }; + let new_cap = if elem_size > (!0) / 8 { 1 } else { 4 }; let ptr = heap::allocate(new_cap * elem_size, align); (new_cap, ptr) } else { @@ -348,7 +339,7 @@ impl RawVec { let elem_size = mem::size_of::(); // Nothing we can really do about these checks :( let required_cap = used_cap.checked_add(needed_extra_cap) - .expect("capacity overflow"); + .expect("capacity overflow"); // Cannot overflow, because `cap <= isize::MAX`, and type of `cap` is `usize`. let double_cap = self.cap * 2; // `double_cap` guarantees exponential growth. diff --git a/src/liballoc/rc.rs b/src/liballoc/rc.rs index e0f635f195..740d13c476 100644 --- a/src/liballoc/rc.rs +++ b/src/liballoc/rc.rs @@ -12,12 +12,12 @@ //! Single-threaded reference-counting pointers. //! -//! The type [`Rc`][rc] provides shared ownership of a value, allocated -//! in the heap. Invoking [`clone`][clone] on `Rc` produces a new pointer -//! to the same value in the heap. When the last `Rc` pointer to a given -//! value is destroyed, the pointed-to value is also destroyed. +//! The type [`Rc`][rc] provides shared ownership of a value of type `T`, +//! allocated in the heap. Invoking [`clone`][clone] on `Rc` produces a new +//! pointer to the same value in the heap. When the last `Rc` pointer to a +//! given value is destroyed, the pointed-to value is also destroyed. //! -//! Shared pointers in Rust disallow mutation by default, and `Rc` is no +//! Shared references in Rust disallow mutation by default, and `Rc` is no //! exception. If you need to mutate through an `Rc`, use [`Cell`][cell] or //! [`RefCell`][refcell]. //! @@ -44,8 +44,9 @@ //! functions][assoc], called using function-like syntax: //! //! ``` -//! # use std::rc::Rc; -//! # let my_rc = Rc::new(()); +//! use std::rc::Rc; +//! let my_rc = Rc::new(()); +//! //! Rc::downgrade(&my_rc); //! ``` //! @@ -229,13 +230,14 @@ use core::hash::{Hash, Hasher}; use core::intrinsics::{abort, assume}; use core::marker; use core::marker::Unsize; -use core::mem::{self, align_of_val, forget, size_of_val, uninitialized}; +use core::mem::{self, align_of_val, forget, size_of, size_of_val, uninitialized}; use core::ops::Deref; use core::ops::CoerceUnsized; use core::ptr::{self, Shared}; use core::convert::From; use heap::deallocate; +use raw_vec::RawVec; struct RcBox { strong: Cell, @@ -252,7 +254,6 @@ struct RcBox { /// that you have to call them as e.g. `Rc::get_mut(&value)` instead of /// `value.get_mut()`. This avoids conflicts with methods of the inner /// type `T`. -#[cfg_attr(stage0, unsafe_no_drop_flag)] #[stable(feature = "rust1", since = "1.0.0")] pub struct Rc { ptr: Shared>, @@ -295,10 +296,13 @@ impl Rc { /// Returns the contained value, if the `Rc` has exactly one strong reference. /// - /// Otherwise, an `Err` is returned with the same `Rc` that was passed in. + /// Otherwise, an [`Err`][result] is returned with the same `Rc` that was + /// passed in. /// /// This will succeed even if there are outstanding weak references. /// + /// [result]: ../../std/result/enum.Result.html + /// /// # Examples /// /// ``` @@ -332,7 +336,11 @@ impl Rc { } } - /// Checks whether `Rc::try_unwrap` would return `Ok`. + /// Checks whether [`Rc::try_unwrap`][try_unwrap] would return + /// [`Ok`][result]. + /// + /// [try_unwrap]: struct.Rc.html#method.try_unwrap + /// [result]: ../../std/result/enum.Result.html /// /// # Examples /// @@ -358,6 +366,31 @@ impl Rc { } } +impl Rc { + /// Constructs a new `Rc` from a string slice. + #[doc(hidden)] + #[unstable(feature = "rustc_private", + reason = "for internal use in rustc", + issue = "0")] + pub fn __from_str(value: &str) -> Rc { + unsafe { + // Allocate enough space for `RcBox`. + let aligned_len = 2 + (value.len() + size_of::() - 1) / size_of::(); + let vec = RawVec::::with_capacity(aligned_len); + let ptr = vec.ptr(); + forget(vec); + // Initialize fields of `RcBox`. + *ptr.offset(0) = 1; // strong: Cell::new(1) + *ptr.offset(1) = 1; // weak: Cell::new(1) + ptr::copy_nonoverlapping(value.as_ptr(), ptr.offset(2) as *mut u8, value.len()); + // Combine the allocation address and the string length into a fat pointer to `RcBox`. + let rcbox_ptr: *mut RcBox = mem::transmute([ptr as usize, value.len()]); + assert!(aligned_len * size_of::() == size_of_val(&*rcbox_ptr)); + Rc { ptr: Shared::new(rcbox_ptr) } + } + } +} + impl Rc { /// Creates a new [`Weak`][weak] pointer to this value. /// @@ -583,8 +616,10 @@ impl Drop for Rc { /// Drops the `Rc`. /// /// This will decrement the strong reference count. If the strong reference - /// count reaches zero then the only other references (if any) are `Weak`, - /// so we `drop` the inner value. + /// count reaches zero then the only other references (if any) are + /// [`Weak`][weak], so we `drop` the inner value. + /// + /// [weak]: struct.Weak.html /// /// # Examples /// @@ -873,7 +908,6 @@ impl From for Rc { /// /// [rc]: struct.Rc.html /// [downgrade]: struct.Rc.html#method.downgrade -#[cfg_attr(stage0, unsafe_no_drop_flag)] #[stable(feature = "rc_weak", since = "1.4.0")] pub struct Weak { ptr: Shared>, diff --git a/src/liballoc_jemalloc/build.rs b/src/liballoc_jemalloc/build.rs index 8b31c5a557..08a1f8ae8c 100644 --- a/src/liballoc_jemalloc/build.rs +++ b/src/liballoc_jemalloc/build.rs @@ -27,6 +27,20 @@ fn main() { let build_dir = PathBuf::from(env::var_os("OUT_DIR").unwrap()); let src_dir = env::current_dir().unwrap(); + // FIXME: This is a hack to support building targets that don't + // support jemalloc alongside hosts that do. The jemalloc build is + // controlled by a feature of the std crate, and if that feature + // changes between targets, it invalidates the fingerprint of + // std's build script (this is a cargo bug); so we must ensure + // that the feature set used by std is the same across all + // targets, which means we have to build the alloc_jemalloc crate + // for targets like emscripten, even if we don't use it. + if target.contains("rumprun") || target.contains("bitrig") || target.contains("openbsd") || + target.contains("msvc") || target.contains("emscripten") || target.contains("fuchsia") { + println!("cargo:rustc-cfg=dummy_jemalloc"); + return; + } + if let Some(jemalloc) = env::var_os("JEMALLOC_OVERRIDE") { let jemalloc = PathBuf::from(jemalloc); println!("cargo:rustc-link-search=native={}", @@ -46,16 +60,16 @@ fn main() { // only msvc returns None for ar so unwrap is okay let ar = build_helper::cc2ar(compiler.path(), &target).unwrap(); let cflags = compiler.args() - .iter() - .map(|s| s.to_str().unwrap()) - .collect::>() - .join(" "); + .iter() + .map(|s| s.to_str().unwrap()) + .collect::>() + .join(" "); let mut stack = src_dir.join("../jemalloc") - .read_dir() - .unwrap() - .map(|e| e.unwrap()) - .collect::>(); + .read_dir() + .unwrap() + .map(|e| e.unwrap()) + .collect::>(); while let Some(entry) = stack.pop() { let path = entry.path(); if entry.file_type().unwrap().is_dir() { @@ -137,10 +151,10 @@ fn main() { run(&mut cmd); run(Command::new("make") - .current_dir(&build_dir) - .arg("build_lib_static") - .arg("-j") - .arg(env::var("NUM_JOBS").expect("NUM_JOBS was not set"))); + .current_dir(&build_dir) + .arg("build_lib_static") + .arg("-j") + .arg(env::var("NUM_JOBS").expect("NUM_JOBS was not set"))); if target.contains("windows") { println!("cargo:rustc-link-lib=static=jemalloc"); diff --git a/src/liballoc_jemalloc/lib.rs b/src/liballoc_jemalloc/lib.rs index 5bbf1c35e0..21e45f9c4b 100644 --- a/src/liballoc_jemalloc/lib.rs +++ b/src/liballoc_jemalloc/lib.rs @@ -23,124 +23,170 @@ extern crate libc; -use libc::{c_int, c_void, size_t}; +pub use imp::*; -// Linkage directives to pull in jemalloc and its dependencies. -// -// On some platforms we need to be sure to link in `pthread` which jemalloc -// depends on, and specifically on android we need to also link to libgcc. -// Currently jemalloc is compiled with gcc which will generate calls to -// intrinsics that are libgcc specific (e.g. those intrinsics aren't present in -// libcompiler-rt), so link that in to get that support. -#[link(name = "jemalloc", kind = "static")] -#[cfg_attr(target_os = "android", link(name = "gcc"))] -#[cfg_attr(all(not(windows), - not(target_os = "android"), - not(target_env = "musl")), - link(name = "pthread"))] -#[cfg(not(cargobuild))] -extern "C" {} - -// Note that the symbols here are prefixed by default on OSX and Windows (we -// don't explicitly request it), and on Android and DragonFly we explicitly -// request it as unprefixing cause segfaults (mismatches in allocators). -extern "C" { - #[cfg_attr(any(target_os = "macos", target_os = "android", target_os = "ios", - target_os = "dragonfly", target_os = "windows"), - link_name = "je_mallocx")] - fn mallocx(size: size_t, flags: c_int) -> *mut c_void; - #[cfg_attr(any(target_os = "macos", target_os = "android", target_os = "ios", - target_os = "dragonfly", target_os = "windows"), - link_name = "je_rallocx")] - fn rallocx(ptr: *mut c_void, size: size_t, flags: c_int) -> *mut c_void; - #[cfg_attr(any(target_os = "macos", target_os = "android", target_os = "ios", - target_os = "dragonfly", target_os = "windows"), - link_name = "je_xallocx")] - fn xallocx(ptr: *mut c_void, size: size_t, extra: size_t, flags: c_int) -> size_t; - #[cfg_attr(any(target_os = "macos", target_os = "android", target_os = "ios", - target_os = "dragonfly", target_os = "windows"), - link_name = "je_sdallocx")] - fn sdallocx(ptr: *mut c_void, size: size_t, flags: c_int); - #[cfg_attr(any(target_os = "macos", target_os = "android", target_os = "ios", - target_os = "dragonfly", target_os = "windows"), - link_name = "je_nallocx")] - fn nallocx(size: size_t, flags: c_int) -> size_t; -} +// See comments in build.rs for why we sometimes build a crate that does nothing +#[cfg(not(dummy_jemalloc))] +mod imp { + use libc::{c_int, c_void, size_t}; -// The minimum alignment guaranteed by the architecture. This value is used to -// add fast paths for low alignment values. In practice, the alignment is a -// constant at the call site and the branch will be optimized out. -#[cfg(all(any(target_arch = "arm", - target_arch = "mips", - target_arch = "powerpc")))] -const MIN_ALIGN: usize = 8; -#[cfg(all(any(target_arch = "x86", - target_arch = "x86_64", - target_arch = "aarch64", - target_arch = "powerpc64", - target_arch = "mips64", - target_arch = "s390x")))] -const MIN_ALIGN: usize = 16; - -// MALLOCX_ALIGN(a) macro -fn mallocx_align(a: usize) -> c_int { - a.trailing_zeros() as c_int -} + // Linkage directives to pull in jemalloc and its dependencies. + // + // On some platforms we need to be sure to link in `pthread` which jemalloc + // depends on, and specifically on android we need to also link to libgcc. + // Currently jemalloc is compiled with gcc which will generate calls to + // intrinsics that are libgcc specific (e.g. those intrinsics aren't present in + // libcompiler-rt), so link that in to get that support. + #[link(name = "jemalloc", kind = "static")] + #[cfg_attr(target_os = "android", link(name = "gcc"))] + #[cfg_attr(all(not(windows), + not(target_os = "android"), + not(target_env = "musl")), + link(name = "pthread"))] + #[cfg(not(cargobuild))] + extern "C" {} + + // Note that the symbols here are prefixed by default on OSX and Windows (we + // don't explicitly request it), and on Android and DragonFly we explicitly + // request it as unprefixing cause segfaults (mismatches in allocators). + extern "C" { + #[cfg_attr(any(target_os = "macos", target_os = "android", target_os = "ios", + target_os = "dragonfly", target_os = "windows"), + link_name = "je_mallocx")] + fn mallocx(size: size_t, flags: c_int) -> *mut c_void; + #[cfg_attr(any(target_os = "macos", target_os = "android", target_os = "ios", + target_os = "dragonfly", target_os = "windows"), + link_name = "je_rallocx")] + fn rallocx(ptr: *mut c_void, size: size_t, flags: c_int) -> *mut c_void; + #[cfg_attr(any(target_os = "macos", target_os = "android", target_os = "ios", + target_os = "dragonfly", target_os = "windows"), + link_name = "je_xallocx")] + fn xallocx(ptr: *mut c_void, size: size_t, extra: size_t, flags: c_int) -> size_t; + #[cfg_attr(any(target_os = "macos", target_os = "android", target_os = "ios", + target_os = "dragonfly", target_os = "windows"), + link_name = "je_sdallocx")] + fn sdallocx(ptr: *mut c_void, size: size_t, flags: c_int); + #[cfg_attr(any(target_os = "macos", target_os = "android", target_os = "ios", + target_os = "dragonfly", target_os = "windows"), + link_name = "je_nallocx")] + fn nallocx(size: size_t, flags: c_int) -> size_t; + } + + // The minimum alignment guaranteed by the architecture. This value is used to + // add fast paths for low alignment values. In practice, the alignment is a + // constant at the call site and the branch will be optimized out. + #[cfg(all(any(target_arch = "arm", + target_arch = "mips", + target_arch = "powerpc")))] + const MIN_ALIGN: usize = 8; + #[cfg(all(any(target_arch = "x86", + target_arch = "x86_64", + target_arch = "aarch64", + target_arch = "powerpc64", + target_arch = "mips64", + target_arch = "s390x")))] + const MIN_ALIGN: usize = 16; + + // MALLOCX_ALIGN(a) macro + fn mallocx_align(a: usize) -> c_int { + a.trailing_zeros() as c_int + } + + fn align_to_flags(align: usize) -> c_int { + if align <= MIN_ALIGN { + 0 + } else { + mallocx_align(align) + } + } + + #[no_mangle] + pub extern "C" fn __rust_allocate(size: usize, align: usize) -> *mut u8 { + let flags = align_to_flags(align); + unsafe { mallocx(size as size_t, flags) as *mut u8 } + } + + #[no_mangle] + pub extern "C" fn __rust_reallocate(ptr: *mut u8, + _old_size: usize, + size: usize, + align: usize) + -> *mut u8 { + let flags = align_to_flags(align); + unsafe { rallocx(ptr as *mut c_void, size as size_t, flags) as *mut u8 } + } + + #[no_mangle] + pub extern "C" fn __rust_reallocate_inplace(ptr: *mut u8, + _old_size: usize, + size: usize, + align: usize) + -> usize { + let flags = align_to_flags(align); + unsafe { xallocx(ptr as *mut c_void, size as size_t, 0, flags) as usize } + } -fn align_to_flags(align: usize) -> c_int { - if align <= MIN_ALIGN { + #[no_mangle] + pub extern "C" fn __rust_deallocate(ptr: *mut u8, old_size: usize, align: usize) { + let flags = align_to_flags(align); + unsafe { sdallocx(ptr as *mut c_void, old_size as size_t, flags) } + } + + #[no_mangle] + pub extern "C" fn __rust_usable_size(size: usize, align: usize) -> usize { + let flags = align_to_flags(align); + unsafe { nallocx(size as size_t, flags) as usize } + } + + // These symbols are used by jemalloc on android but the really old android + // we're building on doesn't have them defined, so just make sure the symbols + // are available. + #[no_mangle] + #[cfg(target_os = "android")] + pub extern "C" fn pthread_atfork(_prefork: *mut u8, + _postfork_parent: *mut u8, + _postfork_child: *mut u8) + -> i32 { 0 - } else { - mallocx_align(align) } } -#[no_mangle] -pub extern "C" fn __rust_allocate(size: usize, align: usize) -> *mut u8 { - let flags = align_to_flags(align); - unsafe { mallocx(size as size_t, flags) as *mut u8 } -} +#[cfg(dummy_jemalloc)] +mod imp { + fn bogus() -> ! { + panic!("jemalloc is not implemented for this platform"); + } -#[no_mangle] -pub extern "C" fn __rust_reallocate(ptr: *mut u8, - _old_size: usize, - size: usize, - align: usize) - -> *mut u8 { - let flags = align_to_flags(align); - unsafe { rallocx(ptr as *mut c_void, size as size_t, flags) as *mut u8 } -} + #[no_mangle] + pub extern "C" fn __rust_allocate(_size: usize, _align: usize) -> *mut u8 { + bogus() + } -#[no_mangle] -pub extern "C" fn __rust_reallocate_inplace(ptr: *mut u8, - _old_size: usize, - size: usize, - align: usize) - -> usize { - let flags = align_to_flags(align); - unsafe { xallocx(ptr as *mut c_void, size as size_t, 0, flags) as usize } -} + #[no_mangle] + pub extern "C" fn __rust_reallocate(_ptr: *mut u8, + _old_size: usize, + _size: usize, + _align: usize) + -> *mut u8 { + bogus() + } -#[no_mangle] -pub extern "C" fn __rust_deallocate(ptr: *mut u8, old_size: usize, align: usize) { - let flags = align_to_flags(align); - unsafe { sdallocx(ptr as *mut c_void, old_size as size_t, flags) } -} + #[no_mangle] + pub extern "C" fn __rust_reallocate_inplace(_ptr: *mut u8, + _old_size: usize, + _size: usize, + _align: usize) + -> usize { + bogus() + } -#[no_mangle] -pub extern "C" fn __rust_usable_size(size: usize, align: usize) -> usize { - let flags = align_to_flags(align); - unsafe { nallocx(size as size_t, flags) as usize } -} + #[no_mangle] + pub extern "C" fn __rust_deallocate(_ptr: *mut u8, _old_size: usize, _align: usize) { + bogus() + } -// These symbols are used by jemalloc on android but the really old android -// we're building on doesn't have them defined, so just make sure the symbols -// are available. -#[no_mangle] -#[cfg(target_os = "android")] -pub extern "C" fn pthread_atfork(_prefork: *mut u8, - _postfork_parent: *mut u8, - _postfork_child: *mut u8) - -> i32 { - 0 + #[no_mangle] + pub extern "C" fn __rust_usable_size(_size: usize, _align: usize) -> usize { + bogus() + } } diff --git a/src/liballoc_system/lib.rs b/src/liballoc_system/lib.rs index 01407d1acd..a4fabb5a2c 100644 --- a/src/liballoc_system/lib.rs +++ b/src/liballoc_system/lib.rs @@ -29,7 +29,8 @@ target_arch = "mips", target_arch = "powerpc", target_arch = "powerpc64", - target_arch = "asmjs")))] + target_arch = "asmjs", + target_arch = "wasm32")))] const MIN_ALIGN: usize = 8; #[cfg(all(any(target_arch = "x86_64", target_arch = "aarch64", @@ -165,6 +166,7 @@ mod imp { fn HeapAlloc(hHeap: HANDLE, dwFlags: DWORD, dwBytes: SIZE_T) -> LPVOID; fn HeapReAlloc(hHeap: HANDLE, dwFlags: DWORD, lpMem: LPVOID, dwBytes: SIZE_T) -> LPVOID; fn HeapFree(hHeap: HANDLE, dwFlags: DWORD, lpMem: LPVOID) -> BOOL; + fn GetLastError() -> DWORD; } #[repr(C)] @@ -220,11 +222,7 @@ mod imp { HEAP_REALLOC_IN_PLACE_ONLY, ptr as LPVOID, size as SIZE_T) as *mut u8; - if new.is_null() { - old_size - } else { - size - } + if new.is_null() { old_size } else { size } } else { old_size } @@ -233,11 +231,11 @@ mod imp { pub unsafe fn deallocate(ptr: *mut u8, _old_size: usize, align: usize) { if align <= MIN_ALIGN { let err = HeapFree(GetProcessHeap(), 0, ptr as LPVOID); - debug_assert!(err != 0); + debug_assert!(err != 0, "Failed to free heap memory: {}", GetLastError()); } else { let header = get_header(ptr); let err = HeapFree(GetProcessHeap(), 0, header.0 as LPVOID); - debug_assert!(err != 0); + debug_assert!(err != 0, "Failed to free heap memory: {}", GetLastError()); } } diff --git a/src/libarena/lib.rs b/src/libarena/lib.rs index 4986c9850d..6044bec2c5 100644 --- a/src/libarena/lib.rs +++ b/src/libarena/lib.rs @@ -46,6 +46,7 @@ use std::intrinsics; use std::marker::{PhantomData, Send}; use std::mem; use std::ptr; +use std::slice; use alloc::heap; use alloc::raw_vec::RawVec; @@ -133,7 +134,7 @@ impl TypedArena { #[inline] pub fn alloc(&self, object: T) -> &mut T { if self.ptr == self.end { - self.grow() + self.grow(1) } unsafe { @@ -154,24 +155,58 @@ impl TypedArena { } } + /// Allocates a slice of objects that are copy into the `TypedArena`, returning a mutable + /// reference to it. Will panic if passed a zero-sized types. + /// + /// Panics: + /// - Zero-sized types + /// - Zero-length slices + #[inline] + pub fn alloc_slice(&self, slice: &[T]) -> &mut [T] + where T: Copy { + assert!(mem::size_of::() != 0); + assert!(slice.len() != 0); + + let available_capacity_bytes = self.end.get() as usize - self.ptr.get() as usize; + let at_least_bytes = slice.len() * mem::size_of::(); + if available_capacity_bytes < at_least_bytes { + self.grow(slice.len()); + } + + unsafe { + let start_ptr = self.ptr.get(); + let arena_slice = slice::from_raw_parts_mut(start_ptr, slice.len()); + self.ptr.set(start_ptr.offset(arena_slice.len() as isize)); + arena_slice.copy_from_slice(slice); + arena_slice + } + } + /// Grows the arena. #[inline(never)] #[cold] - fn grow(&self) { + fn grow(&self, n: usize) { unsafe { let mut chunks = self.chunks.borrow_mut(); - let (chunk, new_capacity); + let (chunk, mut new_capacity); if let Some(last_chunk) = chunks.last_mut() { - if last_chunk.storage.double_in_place() { + let used_bytes = self.ptr.get() as usize - last_chunk.start() as usize; + let currently_used_cap = used_bytes / mem::size_of::(); + if last_chunk.storage.reserve_in_place(currently_used_cap, n) { self.end.set(last_chunk.end()); return; } else { let prev_capacity = last_chunk.storage.cap(); - new_capacity = prev_capacity.checked_mul(2).unwrap(); + loop { + new_capacity = prev_capacity.checked_mul(2).unwrap(); + if new_capacity >= currently_used_cap + n { + break; + } + } } } else { let elem_size = cmp::max(1, mem::size_of::()); - new_capacity = cmp::max(1, PAGE / elem_size); + new_capacity = cmp::max(n, PAGE / elem_size); } chunk = TypedArenaChunk::::new(new_capacity); self.ptr.set(chunk.start()); @@ -302,9 +337,8 @@ mod tests { let arena = Wrap(TypedArena::new()); - let result = arena.alloc_outer(|| { - Outer { inner: arena.alloc_inner(|| Inner { value: 10 }) } - }); + let result = + arena.alloc_outer(|| Outer { inner: arena.alloc_inner(|| Inner { value: 10 }) }); assert_eq!(result.inner.value, 10); } diff --git a/src/libcollections/binary_heap.rs b/src/libcollections/binary_heap.rs index 5f2401b236..b4be8a4321 100644 --- a/src/libcollections/binary_heap.rs +++ b/src/libcollections/binary_heap.rs @@ -1033,7 +1033,7 @@ pub struct Drain<'a, T: 'a> { iter: vec::Drain<'a, T>, } -#[stable(feature = "rust1", since = "1.0.0")] +#[stable(feature = "drain", since = "1.6.0")] impl<'a, T: 'a> Iterator for Drain<'a, T> { type Item = T; @@ -1048,7 +1048,7 @@ impl<'a, T: 'a> Iterator for Drain<'a, T> { } } -#[stable(feature = "rust1", since = "1.0.0")] +#[stable(feature = "drain", since = "1.6.0")] impl<'a, T: 'a> DoubleEndedIterator for Drain<'a, T> { #[inline] fn next_back(&mut self) -> Option { @@ -1056,7 +1056,7 @@ impl<'a, T: 'a> DoubleEndedIterator for Drain<'a, T> { } } -#[stable(feature = "rust1", since = "1.0.0")] +#[stable(feature = "drain", since = "1.6.0")] impl<'a, T: 'a> ExactSizeIterator for Drain<'a, T> {} #[unstable(feature = "fused", issue = "35602")] diff --git a/src/libcollections/borrow.rs b/src/libcollections/borrow.rs index 700f88dc0f..37618b7600 100644 --- a/src/libcollections/borrow.rs +++ b/src/libcollections/borrow.rs @@ -14,9 +14,10 @@ use core::cmp::Ordering; use core::hash::{Hash, Hasher}; -use core::ops::Deref; +use core::ops::{Add, AddAssign, Deref}; use fmt; +use string::String; use self::Cow::*; @@ -86,16 +87,29 @@ impl ToOwned for T where T: Clone { /// ``` /// use std::borrow::Cow; /// -/// # #[allow(dead_code)] /// fn abs_all(input: &mut Cow<[i32]>) { /// for i in 0..input.len() { /// let v = input[i]; /// if v < 0 { -/// // clones into a vector the first time (if not already owned) +/// // Clones into a vector if not already owned. /// input.to_mut()[i] = -v; /// } /// } /// } +/// +/// // No clone occurs because `input` doesn't need to be mutated. +/// let slice = [0, 1, 2]; +/// let mut input = Cow::from(&slice[..]); +/// abs_all(&mut input); +/// +/// // Clone occurs because `input` needs to be mutated. +/// let slice = [-1, 0, 1]; +/// let mut input = Cow::from(&slice[..]); +/// abs_all(&mut input); +/// +/// // No clone occurs because `input` is already owned. +/// let mut input = Cow::from(vec![-1, 0, 1]); +/// abs_all(&mut input); /// ``` #[stable(feature = "rust1", since = "1.0.0")] pub enum Cow<'a, B: ?Sized + 'a> @@ -146,7 +160,10 @@ impl<'a, B: ?Sized> Cow<'a, B> where B: ToOwned { match *self { Borrowed(borrowed) => { *self = Owned(borrowed.to_owned()); - self.to_mut() + match *self { + Borrowed(..) => unreachable!(), + Owned(ref mut owned) => owned, + } } Owned(ref mut owned) => owned, } @@ -270,3 +287,61 @@ impl<'a, T: ?Sized + ToOwned> AsRef for Cow<'a, T> { self } } + +#[stable(feature = "cow_add", since = "1.14.0")] +impl<'a> Add<&'a str> for Cow<'a, str> { + type Output = Cow<'a, str>; + + #[inline] + fn add(mut self, rhs: &'a str) -> Self::Output { + self += rhs; + self + } +} + +#[stable(feature = "cow_add", since = "1.14.0")] +impl<'a> Add> for Cow<'a, str> { + type Output = Cow<'a, str>; + + #[inline] + fn add(mut self, rhs: Cow<'a, str>) -> Self::Output { + self += rhs; + self + } +} + +#[stable(feature = "cow_add", since = "1.14.0")] +impl<'a> AddAssign<&'a str> for Cow<'a, str> { + fn add_assign(&mut self, rhs: &'a str) { + if self.is_empty() { + *self = Cow::Borrowed(rhs) + } else if rhs.is_empty() { + return; + } else { + if let Cow::Borrowed(lhs) = *self { + let mut s = String::with_capacity(lhs.len() + rhs.len()); + s.push_str(lhs); + *self = Cow::Owned(s); + } + self.to_mut().push_str(rhs); + } + } +} + +#[stable(feature = "cow_add", since = "1.14.0")] +impl<'a> AddAssign> for Cow<'a, str> { + fn add_assign(&mut self, rhs: Cow<'a, str>) { + if self.is_empty() { + *self = rhs + } else if rhs.is_empty() { + return; + } else { + if let Cow::Borrowed(lhs) = *self { + let mut s = String::with_capacity(lhs.len() + rhs.len()); + s.push_str(lhs); + *self = Cow::Owned(s); + } + self.to_mut().push_str(&rhs); + } + } +} diff --git a/src/libcollections/btree/map.rs b/src/libcollections/btree/map.rs index 36cb5a1fd9..788236c24d 100644 --- a/src/libcollections/btree/map.rs +++ b/src/libcollections/btree/map.rs @@ -136,6 +136,7 @@ pub struct BTreeMap { length: usize, } +#[stable(feature = "btree_drop", since = "1.7.0")] impl Drop for BTreeMap { #[unsafe_destructor_blind_to_params] fn drop(&mut self) { @@ -146,6 +147,7 @@ impl Drop for BTreeMap { } } +#[stable(feature = "rust1", since = "1.0.0")] impl Clone for BTreeMap { fn clone(&self) -> BTreeMap { fn clone_subtree(node: node::NodeRef BTreeMap { } } +#[stable(feature = "rust1", since = "1.0.0")] impl<'a, K: 'a, V: 'a> IntoIterator for &'a BTreeMap { type Item = (&'a K, &'a V); type IntoIter = Iter<'a, K, V>; @@ -1134,6 +1137,7 @@ impl<'a, K: 'a, V: 'a> IntoIterator for &'a BTreeMap { } } +#[stable(feature = "rust1", since = "1.0.0")] impl<'a, K: 'a, V: 'a> Iterator for Iter<'a, K, V> { type Item = (&'a K, &'a V); @@ -1154,6 +1158,7 @@ impl<'a, K: 'a, V: 'a> Iterator for Iter<'a, K, V> { #[unstable(feature = "fused", issue = "35602")] impl<'a, K, V> FusedIterator for Iter<'a, K, V> {} +#[stable(feature = "rust1", since = "1.0.0")] impl<'a, K: 'a, V: 'a> DoubleEndedIterator for Iter<'a, K, V> { fn next_back(&mut self) -> Option<(&'a K, &'a V)> { if self.length == 0 { @@ -1165,12 +1170,14 @@ impl<'a, K: 'a, V: 'a> DoubleEndedIterator for Iter<'a, K, V> { } } +#[stable(feature = "rust1", since = "1.0.0")] impl<'a, K: 'a, V: 'a> ExactSizeIterator for Iter<'a, K, V> { fn len(&self) -> usize { self.length } } +#[stable(feature = "rust1", since = "1.0.0")] impl<'a, K, V> Clone for Iter<'a, K, V> { fn clone(&self) -> Iter<'a, K, V> { Iter { @@ -1180,6 +1187,7 @@ impl<'a, K, V> Clone for Iter<'a, K, V> { } } +#[stable(feature = "rust1", since = "1.0.0")] impl<'a, K: 'a, V: 'a> IntoIterator for &'a mut BTreeMap { type Item = (&'a K, &'a mut V); type IntoIter = IterMut<'a, K, V>; @@ -1189,6 +1197,7 @@ impl<'a, K: 'a, V: 'a> IntoIterator for &'a mut BTreeMap { } } +#[stable(feature = "rust1", since = "1.0.0")] impl<'a, K: 'a, V: 'a> Iterator for IterMut<'a, K, V> { type Item = (&'a K, &'a mut V); @@ -1206,6 +1215,7 @@ impl<'a, K: 'a, V: 'a> Iterator for IterMut<'a, K, V> { } } +#[stable(feature = "rust1", since = "1.0.0")] impl<'a, K: 'a, V: 'a> DoubleEndedIterator for IterMut<'a, K, V> { fn next_back(&mut self) -> Option<(&'a K, &'a mut V)> { if self.length == 0 { @@ -1217,6 +1227,7 @@ impl<'a, K: 'a, V: 'a> DoubleEndedIterator for IterMut<'a, K, V> { } } +#[stable(feature = "rust1", since = "1.0.0")] impl<'a, K: 'a, V: 'a> ExactSizeIterator for IterMut<'a, K, V> { fn len(&self) -> usize { self.length @@ -1226,6 +1237,7 @@ impl<'a, K: 'a, V: 'a> ExactSizeIterator for IterMut<'a, K, V> { #[unstable(feature = "fused", issue = "35602")] impl<'a, K, V> FusedIterator for IterMut<'a, K, V> {} +#[stable(feature = "rust1", since = "1.0.0")] impl IntoIterator for BTreeMap { type Item = (K, V); type IntoIter = IntoIter; @@ -1244,6 +1256,7 @@ impl IntoIterator for BTreeMap { } } +#[stable(feature = "btree_drop", since = "1.7.0")] impl Drop for IntoIter { fn drop(&mut self) { for _ in &mut *self { @@ -1260,6 +1273,7 @@ impl Drop for IntoIter { } } +#[stable(feature = "rust1", since = "1.0.0")] impl Iterator for IntoIter { type Item = (K, V); @@ -1304,6 +1318,7 @@ impl Iterator for IntoIter { } } +#[stable(feature = "rust1", since = "1.0.0")] impl DoubleEndedIterator for IntoIter { fn next_back(&mut self) -> Option<(K, V)> { if self.length == 0 { @@ -1342,6 +1357,7 @@ impl DoubleEndedIterator for IntoIter { } } +#[stable(feature = "rust1", since = "1.0.0")] impl ExactSizeIterator for IntoIter { fn len(&self) -> usize { self.length @@ -1351,6 +1367,7 @@ impl ExactSizeIterator for IntoIter { #[unstable(feature = "fused", issue = "35602")] impl FusedIterator for IntoIter {} +#[stable(feature = "rust1", since = "1.0.0")] impl<'a, K, V> Iterator for Keys<'a, K, V> { type Item = &'a K; @@ -1363,12 +1380,14 @@ impl<'a, K, V> Iterator for Keys<'a, K, V> { } } +#[stable(feature = "rust1", since = "1.0.0")] impl<'a, K, V> DoubleEndedIterator for Keys<'a, K, V> { fn next_back(&mut self) -> Option<&'a K> { self.inner.next_back().map(|(k, _)| k) } } +#[stable(feature = "rust1", since = "1.0.0")] impl<'a, K, V> ExactSizeIterator for Keys<'a, K, V> { fn len(&self) -> usize { self.inner.len() @@ -1378,12 +1397,14 @@ impl<'a, K, V> ExactSizeIterator for Keys<'a, K, V> { #[unstable(feature = "fused", issue = "35602")] impl<'a, K, V> FusedIterator for Keys<'a, K, V> {} +#[stable(feature = "rust1", since = "1.0.0")] impl<'a, K, V> Clone for Keys<'a, K, V> { fn clone(&self) -> Keys<'a, K, V> { Keys { inner: self.inner.clone() } } } +#[stable(feature = "rust1", since = "1.0.0")] impl<'a, K, V> Iterator for Values<'a, K, V> { type Item = &'a V; @@ -1396,12 +1417,14 @@ impl<'a, K, V> Iterator for Values<'a, K, V> { } } +#[stable(feature = "rust1", since = "1.0.0")] impl<'a, K, V> DoubleEndedIterator for Values<'a, K, V> { fn next_back(&mut self) -> Option<&'a V> { self.inner.next_back().map(|(_, v)| v) } } +#[stable(feature = "rust1", since = "1.0.0")] impl<'a, K, V> ExactSizeIterator for Values<'a, K, V> { fn len(&self) -> usize { self.inner.len() @@ -1411,6 +1434,7 @@ impl<'a, K, V> ExactSizeIterator for Values<'a, K, V> { #[unstable(feature = "fused", issue = "35602")] impl<'a, K, V> FusedIterator for Values<'a, K, V> {} +#[stable(feature = "rust1", since = "1.0.0")] impl<'a, K, V> Clone for Values<'a, K, V> { fn clone(&self) -> Values<'a, K, V> { Values { inner: self.inner.clone() } @@ -1635,6 +1659,7 @@ impl<'a, K, V> RangeMut<'a, K, V> { } } +#[stable(feature = "rust1", since = "1.0.0")] impl FromIterator<(K, V)> for BTreeMap { fn from_iter>(iter: T) -> BTreeMap { let mut map = BTreeMap::new(); @@ -1643,6 +1668,7 @@ impl FromIterator<(K, V)> for BTreeMap { } } +#[stable(feature = "rust1", since = "1.0.0")] impl Extend<(K, V)> for BTreeMap { #[inline] fn extend>(&mut self, iter: T) { @@ -1652,12 +1678,14 @@ impl Extend<(K, V)> for BTreeMap { } } +#[stable(feature = "extend_ref", since = "1.2.0")] impl<'a, K: Ord + Copy, V: Copy> Extend<(&'a K, &'a V)> for BTreeMap { fn extend>(&mut self, iter: I) { self.extend(iter.into_iter().map(|(&key, &value)| (key, value))); } } +#[stable(feature = "rust1", since = "1.0.0")] impl Hash for BTreeMap { fn hash(&self, state: &mut H) { for elt in self { @@ -1666,6 +1694,7 @@ impl Hash for BTreeMap { } } +#[stable(feature = "rust1", since = "1.0.0")] impl Default for BTreeMap { /// Creates an empty `BTreeMap`. fn default() -> BTreeMap { @@ -1673,14 +1702,17 @@ impl Default for BTreeMap { } } +#[stable(feature = "rust1", since = "1.0.0")] impl PartialEq for BTreeMap { fn eq(&self, other: &BTreeMap) -> bool { self.len() == other.len() && self.iter().zip(other).all(|(a, b)| a == b) } } +#[stable(feature = "rust1", since = "1.0.0")] impl Eq for BTreeMap {} +#[stable(feature = "rust1", since = "1.0.0")] impl PartialOrd for BTreeMap { #[inline] fn partial_cmp(&self, other: &BTreeMap) -> Option { @@ -1688,6 +1720,7 @@ impl PartialOrd for BTreeMap { } } +#[stable(feature = "rust1", since = "1.0.0")] impl Ord for BTreeMap { #[inline] fn cmp(&self, other: &BTreeMap) -> Ordering { @@ -1695,12 +1728,14 @@ impl Ord for BTreeMap { } } +#[stable(feature = "rust1", since = "1.0.0")] impl Debug for BTreeMap { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { f.debug_map().entries(self.iter()).finish() } } +#[stable(feature = "rust1", since = "1.0.0")] impl<'a, K: Ord, Q: ?Sized, V> Index<&'a Q> for BTreeMap where K: Borrow, Q: Ord diff --git a/src/libcollections/btree/set.rs b/src/libcollections/btree/set.rs index fc2a7f8254..c57266d9e3 100644 --- a/src/libcollections/btree/set.rs +++ b/src/libcollections/btree/set.rs @@ -779,6 +779,7 @@ impl Debug for BTreeSet { } } +#[stable(feature = "rust1", since = "1.0.0")] impl<'a, T> Clone for Iter<'a, T> { fn clone(&self) -> Iter<'a, T> { Iter { iter: self.iter.clone() } @@ -864,6 +865,7 @@ fn cmp_opt(x: Option<&T>, y: Option<&T>, short: Ordering, long: Ordering } } +#[stable(feature = "rust1", since = "1.0.0")] impl<'a, T> Clone for Difference<'a, T> { fn clone(&self) -> Difference<'a, T> { Difference { @@ -901,6 +903,7 @@ impl<'a, T: Ord> Iterator for Difference<'a, T> { #[unstable(feature = "fused", issue = "35602")] impl<'a, T: Ord> FusedIterator for Difference<'a, T> {} +#[stable(feature = "rust1", since = "1.0.0")] impl<'a, T> Clone for SymmetricDifference<'a, T> { fn clone(&self) -> SymmetricDifference<'a, T> { SymmetricDifference { @@ -934,6 +937,7 @@ impl<'a, T: Ord> Iterator for SymmetricDifference<'a, T> { #[unstable(feature = "fused", issue = "35602")] impl<'a, T: Ord> FusedIterator for SymmetricDifference<'a, T> {} +#[stable(feature = "rust1", since = "1.0.0")] impl<'a, T> Clone for Intersection<'a, T> { fn clone(&self) -> Intersection<'a, T> { Intersection { @@ -977,6 +981,7 @@ impl<'a, T: Ord> Iterator for Intersection<'a, T> { #[unstable(feature = "fused", issue = "35602")] impl<'a, T: Ord> FusedIterator for Intersection<'a, T> {} +#[stable(feature = "rust1", since = "1.0.0")] impl<'a, T> Clone for Union<'a, T> { fn clone(&self) -> Union<'a, T> { Union { diff --git a/src/libcollections/enum_set.rs b/src/libcollections/enum_set.rs index 2456a04e40..2d12b4ccff 100644 --- a/src/libcollections/enum_set.rs +++ b/src/libcollections/enum_set.rs @@ -48,7 +48,6 @@ impl Clone for EnumSet { } } -#[stable(feature = "rust1", since = "1.0.0")] impl fmt::Debug for EnumSet { fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result { fmt.debug_set().entries(self).finish() @@ -277,7 +276,6 @@ impl FromIterator for EnumSet { } } -#[stable(feature = "rust1", since = "1.0.0")] impl<'a, E> IntoIterator for &'a EnumSet where E: CLike { type Item = E; @@ -296,7 +294,6 @@ impl Extend for EnumSet { } } -#[stable(feature = "extend_ref", since = "1.2.0")] impl<'a, E: 'a + CLike + Copy> Extend<&'a E> for EnumSet { fn extend>(&mut self, iter: I) { self.extend(iter.into_iter().cloned()); diff --git a/src/libcollections/fmt.rs b/src/libcollections/fmt.rs index beb3e6b3d4..883417e9f4 100644 --- a/src/libcollections/fmt.rs +++ b/src/libcollections/fmt.rs @@ -261,8 +261,8 @@ //! This and `writeln` are two macros which are used to emit the format string //! to a specified stream. This is used to prevent intermediate allocations of //! format strings and instead directly write the output. Under the hood, this -//! function is actually invoking the `write` function defined in this module. -//! Example usage is: +//! function is actually invoking the `write_fmt` function defined on the +//! `std::io::Write` trait. Example usage is: //! //! ``` //! # #![allow(unused_must_use)] @@ -327,7 +327,7 @@ //! format := '{' [ argument ] [ ':' format_spec ] '}' //! argument := integer | identifier //! -//! format_spec := [[fill]align][sign]['#'][0][width]['.' precision][type] +//! format_spec := [[fill]align][sign]['#']['0'][width]['.' precision][type] //! fill := character //! align := '<' | '^' | '>' //! sign := '+' | '-' diff --git a/src/libcollections/lib.rs b/src/libcollections/lib.rs index c5a9216934..23d6edd6d7 100644 --- a/src/libcollections/lib.rs +++ b/src/libcollections/lib.rs @@ -50,9 +50,9 @@ #![feature(specialization)] #![feature(staged_api)] #![feature(step_by)] +#![feature(trusted_len)] #![feature(unicode)] #![feature(unique)] -#![cfg_attr(stage0, feature(unsafe_no_drop_flag))] #![cfg_attr(test, feature(rand, test))] #![no_std] diff --git a/src/libcollections/linked_list.rs b/src/libcollections/linked_list.rs index 690c4f4af3..67f3708a62 100644 --- a/src/libcollections/linked_list.rs +++ b/src/libcollections/linked_list.rs @@ -1294,6 +1294,7 @@ mod tests { } #[test] + #[cfg_attr(target_os = "emscripten", ignore)] fn test_send() { let n = list_from(&[1, 2, 3]); thread::spawn(move || { diff --git a/src/libcollections/macros.rs b/src/libcollections/macros.rs index d6a8362d58..3115be00a4 100644 --- a/src/libcollections/macros.rs +++ b/src/libcollections/macros.rs @@ -68,7 +68,9 @@ macro_rules! vec { } /// Use the syntax described in `std::fmt` to create a value of type `String`. -/// See `std::fmt` for more information. +/// See [`std::fmt`][fmt] for more information. +/// +/// [fmt]: ../std/fmt/index.html /// /// # Examples /// diff --git a/src/libcollections/slice.rs b/src/libcollections/slice.rs index 54dc7ec06d..75796cf94b 100644 --- a/src/libcollections/slice.rs +++ b/src/libcollections/slice.rs @@ -36,7 +36,7 @@ //! //! ## Structs //! -//! There are several structs that are useful for slices, such as `Iter`, which +//! There are several structs that are useful for slices, such as [`Iter`], which //! represents iteration over a slice. //! //! ## Trait Implementations @@ -44,9 +44,9 @@ //! There are several implementations of common traits for slices. Some examples //! include: //! -//! * `Clone` -//! * `Eq`, `Ord` - for slices whose element type are `Eq` or `Ord`. -//! * `Hash` - for slices whose element type is `Hash` +//! * [`Clone`] +//! * [`Eq`], [`Ord`] - for slices whose element type are [`Eq`] or [`Ord`]. +//! * [`Hash`] - for slices whose element type is [`Hash`]. //! //! ## Iteration //! @@ -73,12 +73,24 @@ //! the element type of the slice is `i32`, the element type of the iterator is //! `&mut i32`. //! -//! * `.iter()` and `.iter_mut()` are the explicit methods to return the default +//! * [`.iter()`] and [`.iter_mut()`] are the explicit methods to return the default //! iterators. -//! * Further methods that return iterators are `.split()`, `.splitn()`, -//! `.chunks()`, `.windows()` and more. +//! * Further methods that return iterators are [`.split()`], [`.splitn()`], +//! [`.chunks()`], [`.windows()`] and more. //! //! *[See also the slice primitive type](../../std/primitive.slice.html).* +//! +//! [`Clone`]: ../../std/clone/trait.Clone.html +//! [`Eq`]: ../../std/cmp/trait.Eq.html +//! [`Ord`]: ../../std/cmp/trait.Ord.html +//! [`Iter`]: struct.Iter.html +//! [`Hash`]: ../../std/hash/trait.Hash.html +//! [`.iter()`]: ../../std/primitive.slice.html#method.iter +//! [`.iter_mut()`]: ../../std/primitive.slice.html#method.iter_mut +//! [`.split()`]: ../../std/primitive.slice.html#method.split +//! [`.splitn()`]: ../../std/primitive.slice.html#method.splitn +//! [`.chunks()`]: ../../std/primitive.slice.html#method.chunks +//! [`.windows()`]: ../../std/primitive.slice.html#method.windows #![stable(feature = "rust1", since = "1.0.0")] // Many of the usings in this module are only used in the test configuration. @@ -168,7 +180,7 @@ impl [T] { core_slice::SliceExt::len(self) } - /// Returns true if the slice has a length of 0 + /// Returns true if the slice has a length of 0. /// /// # Example /// @@ -402,7 +414,7 @@ impl [T] { core_slice::SliceExt::get_unchecked_mut(self, index) } - /// Returns an raw pointer to the slice's buffer + /// Returns an raw 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. @@ -468,7 +480,7 @@ impl [T] { /// /// # Examples /// - /// ```rust + /// ``` /// let mut v = ["a", "b", "c", "d"]; /// v.swap(1, 3); /// assert!(v == ["a", "d", "c", "b"]); @@ -483,7 +495,7 @@ impl [T] { /// /// # Example /// - /// ```rust + /// ``` /// let mut v = [1, 2, 3]; /// v.reverse(); /// assert!(v == [3, 2, 1]); @@ -567,9 +579,9 @@ impl [T] { } /// Returns an iterator over `size` elements of the slice at a - /// time. The chunks are slices and do not overlap. If `size` does not divide the - /// length of the slice, then the last chunk will not have length - /// `size`. + /// time. The chunks are slices and do not overlap. If `size` does + /// not divide the length of the slice, then the last chunk will + /// not have length `size`. /// /// # Panics /// @@ -656,7 +668,7 @@ impl [T] { /// /// # Examples /// - /// ```rust + /// ``` /// let mut v = [1, 2, 3, 4, 5, 6]; /// /// // scoped to restrict the lifetime of the borrows @@ -754,7 +766,7 @@ impl [T] { } /// Returns an iterator over subslices separated by elements that match - /// `pred`, limited to returning at most `n` items. The matched element is + /// `pred`, limited to returning at most `n` items. The matched element is /// not contained in the subslices. /// /// The last element returned, if any, will contain the remainder of the @@ -781,7 +793,7 @@ impl [T] { } /// Returns an iterator over subslices separated by elements that match - /// `pred`, limited to returning at most `n` items. The matched element is + /// `pred`, limited to returning at most `n` items. The matched element is /// not contained in the subslices. /// /// The last element returned, if any, will contain the remainder of the @@ -835,7 +847,7 @@ impl [T] { /// Returns an iterator over subslices separated by elements that match /// `pred` limited to returning at most `n` items. This starts at the end of - /// the slice and works backwards. The matched element is not contained in + /// the slice and works backwards. The matched element is not contained in /// the subslices. /// /// The last element returned, if any, will contain the remainder of the @@ -922,9 +934,9 @@ impl [T] { /// /// Looks up a series of four elements. The first is found, with a /// uniquely determined position; the second and third are not - /// found; the fourth could match any position in `[1,4]`. + /// found; the fourth could match any position in `[1, 4]`. /// - /// ```rust + /// ``` /// let s = [0, 1, 1, 1, 1, 2, 3, 5, 8, 13, 21, 34, 55]; /// /// assert_eq!(s.binary_search(&13), Ok(9)); @@ -956,9 +968,9 @@ impl [T] { /// /// Looks up a series of four elements. The first is found, with a /// uniquely determined position; the second and third are not - /// found; the fourth could match any position in `[1,4]`. + /// found; the fourth could match any position in `[1, 4]`. /// - /// ```rust + /// ``` /// let s = [0, 1, 1, 1, 1, 2, 3, 5, 8, 13, 21, 34, 55]; /// /// let seek = 13; @@ -982,21 +994,23 @@ impl [T] { /// Binary search a sorted slice with a key extraction function. /// /// Assumes that the slice is sorted by the key, for instance with - /// `sort_by_key` using the same key extraction function. + /// [`sort_by_key`] using the same key extraction function. /// /// If a matching value is found then returns `Ok`, containing the /// index for the matched element; if no match is found then `Err` /// is returned, containing the index where a matching element could /// be inserted while maintaining sorted order. /// + /// [`sort_by_key`]: #method.sort_by_key + /// /// # Examples /// /// Looks up a series of four elements in a slice of pairs sorted by /// their second elements. The first is found, with a uniquely /// determined position; the second and third are not found; the - /// fourth could match any position in `[1,4]`. + /// fourth could match any position in `[1, 4]`. /// - /// ```rust + /// ``` /// let s = [(0, 0), (2, 1), (4, 1), (5, 1), (3, 1), /// (1, 2), (2, 3), (4, 5), (5, 8), (3, 13), /// (1, 21), (2, 34), (4, 55)]; @@ -1023,7 +1037,7 @@ impl [T] { /// /// # Examples /// - /// ```rust + /// ``` /// let mut v = [-5, 4, 1, -3, 2]; /// /// v.sort(); @@ -1045,7 +1059,7 @@ impl [T] { /// /// # Examples /// - /// ```rust + /// ``` /// let mut v = [-5i32, 4, 1, -3, 2]; /// /// v.sort_by_key(|k| k.abs()); @@ -1067,7 +1081,7 @@ impl [T] { /// /// # Examples /// - /// ```rust + /// ``` /// let mut v = [5, 4, 1, 3, 2]; /// v.sort_by(|a, b| a.cmp(b)); /// assert!(v == [1, 2, 3, 4, 5]); @@ -1094,7 +1108,7 @@ impl [T] { /// /// # Example /// - /// ```rust + /// ``` /// let mut dst = [0, 0, 0]; /// let src = [1, 2, 3]; /// @@ -1116,7 +1130,7 @@ impl [T] { /// /// # Example /// - /// ```rust + /// ``` /// let mut dst = [0, 0, 0]; /// let src = [1, 2, 3]; /// @@ -1156,7 +1170,7 @@ impl [T] { /// let x = s.into_vec(); /// // `s` cannot be used anymore because it has been converted into `x`. /// - /// assert_eq!(x, vec!(10, 40, 30)); + /// assert_eq!(x, vec![10, 40, 30]); /// ``` #[stable(feature = "rust1", since = "1.0.0")] #[inline] diff --git a/src/libcollections/str.rs b/src/libcollections/str.rs index 6a6b450e51..48a74bdecb 100644 --- a/src/libcollections/str.rs +++ b/src/libcollections/str.rs @@ -122,7 +122,7 @@ pub struct EncodeUtf16<'a> { encoder: Utf16Encoder>, } -#[stable(feature = "rust1", since = "1.0.0")] +#[stable(feature = "encode_utf16", since = "1.8.0")] impl<'a> Iterator for EncodeUtf16<'a> { type Item = u16; @@ -697,7 +697,7 @@ impl str { /// /// Basic usage: /// - /// ```rust + /// ``` /// let bananas = "bananas"; /// /// assert!(bananas.ends_with("anas")); @@ -900,7 +900,7 @@ impl str { /// /// It does _not_ give you: /// - /// ```rust,ignore + /// ```,ignore /// assert_eq!(d, &["a", "b", "c"]); /// ``` /// @@ -1053,10 +1053,10 @@ impl str { } /// An iterator over substrings of the given string slice, separated by a - /// pattern, restricted to returning at most `count` items. + /// pattern, restricted to returning at most `n` items. /// - /// The last element returned, if any, will contain the remainder of the - /// string slice. + /// If `n` substrings are returned, the last substring (the `n`th substring) + /// will contain the remainder of the string. /// /// The pattern can be a `&str`, [`char`], or a closure that determines the /// split. @@ -1098,16 +1098,16 @@ impl str { /// assert_eq!(v, ["abc", "defXghi"]); /// ``` #[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 splitn<'a, P: Pattern<'a>>(&'a self, n: usize, pat: P) -> SplitN<'a, P> { + core_str::StrExt::splitn(self, n, pat) } /// An iterator over substrings of this string slice, separated by a /// pattern, starting from the end of the string, restricted to returning - /// at most `count` items. + /// at most `n` items. /// - /// The last element returned, if any, will contain the remainder of the - /// string slice. + /// If `n` substrings are returned, the last substring (the `n`th substring) + /// will contain the remainder of the string. /// /// The pattern can be a `&str`, [`char`], or a closure that /// determines the split. @@ -1145,10 +1145,10 @@ impl str { /// assert_eq!(v, ["ghi", "abc1def"]); /// ``` #[stable(feature = "rust1", since = "1.0.0")] - pub fn rsplitn<'a, P: Pattern<'a>>(&'a self, count: usize, pat: P) -> RSplitN<'a, P> + pub fn rsplitn<'a, P: Pattern<'a>>(&'a self, n: usize, pat: P) -> RSplitN<'a, P> where P::Searcher: ReverseSearcher<'a> { - core_str::StrExt::rsplitn(self, count, pat) + core_str::StrExt::rsplitn(self, n, pat) } /// An iterator over the matches of a pattern within the given string @@ -1789,4 +1789,24 @@ impl str { String::from_utf8_unchecked(slice.into_vec()) } } + + /// Create a [`String`] by repeating a string `n` times. + /// + /// [`String`]: string/struct.String.html + /// + /// # Examples + /// + /// Basic usage: + /// + /// ``` + /// #![feature(repeat_str)] + /// + /// assert_eq!("abc".repeat(4), String::from("abcabcabcabc")); + /// ``` + #[unstable(feature = "repeat_str", issue = "37079")] + pub fn repeat(&self, n: usize) -> String { + let mut s = String::with_capacity(self.len() * n); + s.extend((0..n).map(|_| self)); + s + } } diff --git a/src/libcollections/string.rs b/src/libcollections/string.rs index cff0308d4a..348eb6fb5f 100644 --- a/src/libcollections/string.rs +++ b/src/libcollections/string.rs @@ -14,24 +14,25 @@ //! [`ToString`]s, and several error types that may result from working with //! [`String`]s. //! -//! [`String`]: struct.String.html //! [`ToString`]: trait.ToString.html //! //! # Examples //! -//! There are multiple ways to create a new `String` from a string literal: +//! There are multiple ways to create a new [`String`] from a string literal: //! -//! ```rust +//! ``` //! let s = "Hello".to_string(); //! //! let s = String::from("world"); //! let s: String = "also this".into(); //! ``` //! -//! You can create a new `String` from an existing one by concatenating with +//! You can create a new [`String`] from an existing one by concatenating with //! `+`: //! -//! ```rust +//! [`String`]: struct.String.html +//! +//! ``` //! let s = "Hello".to_string(); //! //! let message = s + " world!"; @@ -40,7 +41,7 @@ //! If you have a vector of valid UTF-8 bytes, you can make a `String` out of //! it. You can do the reverse too. //! -//! ```rust +//! ``` //! let sparkle_heart = vec![240, 159, 146, 150]; //! //! // We know these bytes are valid, so we'll use `unwrap()`. @@ -134,10 +135,10 @@ use boxed::Box; /// Indexing is intended to be a constant-time operation, but UTF-8 encoding /// does not allow us to do this. Furthermore, it's not clear what sort of /// thing the index should return: a byte, a codepoint, or a grapheme cluster. -/// The [`as_bytes()`] and [`chars()`] methods return iterators over the first +/// The [`bytes()`] and [`chars()`] methods return iterators over the first /// two, respectively. /// -/// [`as_bytes()`]: #method.as_bytes +/// [`bytes()`]: #method.bytes /// [`chars()`]: #method.chars /// /// # Deref @@ -975,7 +976,7 @@ impl String { pub fn push(&mut self, ch: char) { match ch.len_utf8() { 1 => self.vec.push(ch as u8), - _ => self.vec.extend_from_slice(ch.encode_utf8().as_slice()), + _ => self.vec.extend_from_slice(ch.encode_utf8(&mut [0;4]).as_bytes()), } } @@ -1131,10 +1132,11 @@ impl String { let len = self.len(); assert!(idx <= len); assert!(self.is_char_boundary(idx)); - let bits = ch.encode_utf8(); + let mut bits = [0; 4]; + let bits = ch.encode_utf8(&mut bits).as_bytes(); unsafe { - self.insert_bytes(idx, bits.as_slice()); + self.insert_bytes(idx, bits); } } @@ -1858,6 +1860,13 @@ impl<'a> From<&'a str> for String { } } +#[stable(feature = "string_from_cow_str", since = "1.14.0")] +impl<'a> From> for String { + fn from(s: Cow<'a, str>) -> String { + s.into_owned() + } +} + #[stable(feature = "rust1", since = "1.0.0")] impl<'a> From<&'a str> for Cow<'a, str> { #[inline] @@ -1895,10 +1904,10 @@ impl<'a> FromIterator for Cow<'a, str> { } } -#[stable(feature = "rust1", since = "1.0.0")] -impl Into> for String { - fn into(self) -> Vec { - self.into_bytes() +#[stable(feature = "from_string_for_vec_u8", since = "1.14.0")] +impl From for Vec { + fn from(string : String) -> Vec { + string.into_bytes() } } diff --git a/src/libcollections/vec.rs b/src/libcollections/vec.rs index f8b4a92df2..71c49ee616 100644 --- a/src/libcollections/vec.rs +++ b/src/libcollections/vec.rs @@ -16,13 +16,13 @@ //! //! # Examples //! -//! You can explicitly create a `Vec` with `new()`: +//! You can explicitly create a [`Vec`] with [`new()`]: //! //! ``` //! let v: Vec = Vec::new(); //! ``` //! -//! ...or by using the `vec!` macro: +//! ...or by using the [`vec!`] macro: //! //! ``` //! let v: Vec = vec![]; @@ -32,7 +32,7 @@ //! let v = vec![0; 10]; // ten zeroes //! ``` //! -//! You can `push` values onto the end of a vector (which will grow the vector +//! You can [`push`] values onto the end of a vector (which will grow the vector //! as needed): //! //! ``` @@ -49,13 +49,20 @@ //! let two = v.pop(); //! ``` //! -//! Vectors also support indexing (through the `Index` and `IndexMut` traits): +//! Vectors also support indexing (through the [`Index`] and [`IndexMut`] traits): //! //! ``` //! let mut v = vec![1, 2, 3]; //! let three = v[2]; //! v[1] = v[1] + 5; //! ``` +//! +//! [`Vec`]: ../../std/vec/struct.Vec.html +//! [`new()`]: ../../std/vec/struct.Vec.html#method.new +//! [`push`]: ../../std/vec/struct.Vec.html#method.push +//! [`Index`]: ../../std/ops/trait.Index.html +//! [`IndexMut`]: ../../std/ops/trait.IndexMut.html +//! [`vec!`]: ../../std/macro.vec.html #![stable(feature = "rust1", since = "1.0.0")] @@ -68,7 +75,7 @@ use core::cmp::Ordering; use core::fmt; use core::hash::{self, Hash}; use core::intrinsics::{arith_offset, assume}; -use core::iter::{FromIterator, FusedIterator}; +use core::iter::{FromIterator, FusedIterator, TrustedLen}; use core::mem; use core::ops::{Index, IndexMut}; use core::ops; @@ -76,10 +83,9 @@ use core::ptr; use core::ptr::Shared; use core::slice; -use super::SpecExtend; use super::range::RangeArgument; -/// A contiguous growable array type, written `Vec` but pronounced 'vector.' +/// A contiguous growable array type, written `Vec` but pronounced 'vector'. /// /// # Examples /// @@ -105,7 +111,7 @@ use super::range::RangeArgument; /// assert_eq!(vec, [7, 1, 2, 3]); /// ``` /// -/// The `vec!` macro is provided to make initialization more convenient: +/// The [`vec!`] macro is provided to make initialization more convenient: /// /// ``` /// let mut vec = vec![1, 2, 3]; @@ -137,19 +143,19 @@ use super::range::RangeArgument; /// /// # Indexing /// -/// The Vec type allows to access values by index, because it implements the -/// `Index` trait. An example will be more explicit: +/// The `Vec` type allows to access values by index, because it implements the +/// [`Index`] trait. An example will be more explicit: /// /// ``` -/// let v = vec!(0, 2, 4, 6); +/// let v = vec![0, 2, 4, 6]; /// println!("{}", v[1]); // it will display '2' /// ``` /// -/// However be careful: if you try to access an index which isn't in the Vec, +/// However be careful: if you try to access an index which isn't in the `Vec`, /// your software will panic! You cannot do this: /// /// ```ignore -/// let v = vec!(0, 2, 4, 6); +/// let v = vec![0, 2, 4, 6]; /// println!("{}", v[6]); // it will panic! /// ``` /// @@ -158,15 +164,15 @@ use super::range::RangeArgument; /// /// # Slicing /// -/// A Vec can be mutable. Slices, on the other hand, are read-only objects. -/// To get a slice, use "&". Example: +/// A `Vec` can be mutable. Slices, on the other hand, are read-only objects. +/// To get a slice, use `&`. Example: /// /// ``` /// fn read_slice(slice: &[usize]) { /// // ... /// } /// -/// let v = vec!(0, 1); +/// let v = vec![0, 1]; /// read_slice(&v); /// /// // ... and that's all! @@ -175,8 +181,8 @@ use super::range::RangeArgument; /// ``` /// /// In Rust, it's more common to pass slices as arguments rather than vectors -/// when you just want to provide a read access. The same goes for String and -/// &str. +/// when you just want to provide a read access. The same goes for [`String`] and +/// [`&str`]. /// /// # Capacity and reallocation /// @@ -191,84 +197,100 @@ use super::range::RangeArgument; /// with space for 10 more elements. Pushing 10 or fewer elements onto the /// vector will not change its capacity or cause reallocation to occur. However, /// if the vector's length is increased to 11, it will have to reallocate, which -/// can be slow. For this reason, it is recommended to use `Vec::with_capacity` +/// can be slow. For this reason, it is recommended to use [`Vec::with_capacity`] /// whenever possible to specify how big the vector is expected to get. /// /// # Guarantees /// -/// Due to its incredibly fundamental nature, Vec makes a lot of guarantees +/// Due to its incredibly fundamental nature, `Vec` makes a lot of guarantees /// about its design. This ensures that it's as low-overhead as possible in /// the general case, and can be correctly manipulated in primitive ways /// by unsafe code. Note that these guarantees refer to an unqualified `Vec`. /// If additional type parameters are added (e.g. to support custom allocators), /// overriding their defaults may change the behavior. /// -/// Most fundamentally, Vec is and always will be a (pointer, capacity, length) +/// Most fundamentally, `Vec` is and always will be a (pointer, capacity, length) /// triplet. No more, no less. The order of these fields is completely /// unspecified, and you should use the appropriate methods to modify these. /// The pointer will never be null, so this type is null-pointer-optimized. /// /// However, the pointer may not actually point to allocated memory. In particular, -/// if you construct a Vec with capacity 0 via `Vec::new()`, `vec![]`, -/// `Vec::with_capacity(0)`, or by calling `shrink_to_fit()` on an empty Vec, it -/// will not allocate memory. Similarly, if you store zero-sized types inside -/// a Vec, it will not allocate space for them. *Note that in this case the -/// Vec may not report a `capacity()` of 0*. Vec will allocate if and only -/// if `mem::size_of::() * capacity() > 0`. In general, Vec's allocation +/// if you construct a `Vec` with capacity 0 via [`Vec::new()`], [`vec![]`][`vec!`], +/// [`Vec::with_capacity(0)`][`Vec::with_capacity`], or by calling [`shrink_to_fit()`] +/// on an empty Vec, it will not allocate memory. Similarly, if you store zero-sized +/// types inside a `Vec`, it will not allocate space for them. *Note that in this case +/// the `Vec` may not report a [`capacity()`] of 0*. `Vec` will allocate if and only +/// if [`mem::size_of::()`]` * capacity() > 0`. In general, `Vec`'s allocation /// details are subtle enough that it is strongly recommended that you only -/// free memory allocated by a Vec by creating a new Vec and dropping it. +/// free memory allocated by a `Vec` by creating a new `Vec` and dropping it. /// -/// If a Vec *has* allocated memory, then the memory it points to is on the heap +/// If a `Vec` *has* allocated memory, then the memory it points to is on the heap /// (as defined by the allocator Rust is configured to use by default), and its -/// pointer points to `len()` initialized elements in order (what you would see -/// if you coerced it to a slice), followed by `capacity() - len()` logically -/// uninitialized elements. +/// pointer points to [`len()`] initialized elements in order (what you would see +/// if you coerced it to a slice), followed by [`capacity()`]` - `[`len()`] +/// logically uninitialized elements. /// -/// Vec will never perform a "small optimization" where elements are actually +/// `Vec` will never perform a "small optimization" where elements are actually /// stored on the stack for two reasons: /// /// * It would make it more difficult for unsafe code to correctly manipulate -/// a Vec. The contents of a Vec wouldn't have a stable address if it were -/// only moved, and it would be more difficult to determine if a Vec had +/// a `Vec`. The contents of a `Vec` wouldn't have a stable address if it were +/// only moved, and it would be more difficult to determine if a `Vec` had /// actually allocated memory. /// /// * It would penalize the general case, incurring an additional branch /// on every access. /// -/// Vec will never automatically shrink itself, even if completely empty. This -/// ensures no unnecessary allocations or deallocations occur. Emptying a Vec -/// and then filling it back up to the same `len()` should incur no calls to -/// the allocator. If you wish to free up unused memory, use `shrink_to_fit`. +/// `Vec` will never automatically shrink itself, even if completely empty. This +/// ensures no unnecessary allocations or deallocations occur. Emptying a `Vec` +/// and then filling it back up to the same [`len()`] should incur no calls to +/// the allocator. If you wish to free up unused memory, use +/// [`shrink_to_fit`][`shrink_to_fit()`]. /// -/// `push` and `insert` will never (re)allocate if the reported capacity is -/// sufficient. `push` and `insert` *will* (re)allocate if `len() == capacity()`. -/// That is, the reported capacity is completely accurate, and can be relied on. -/// It can even be used to manually free the memory allocated by a Vec if -/// desired. Bulk insertion methods *may* reallocate, even when not necessary. +/// [`push`] and [`insert`] will never (re)allocate if the reported capacity is +/// sufficient. [`push`] and [`insert`] *will* (re)allocate if +/// [`len()`]` == `[`capacity()`]. That is, the reported capacity is completely +/// accurate, and can be relied on. It can even be used to manually free the memory +/// allocated by a `Vec` if desired. Bulk insertion methods *may* reallocate, even +/// when not necessary. /// -/// Vec does not guarantee any particular growth strategy when reallocating -/// when full, nor when `reserve` is called. The current strategy is basic +/// `Vec` does not guarantee any particular growth strategy when reallocating +/// when full, nor when [`reserve`] is called. The current strategy is basic /// and it may prove desirable to use a non-constant growth factor. Whatever -/// strategy is used will of course guarantee `O(1)` amortized `push`. +/// strategy is used will of course guarantee `O(1)` amortized [`push`]. /// -/// `vec![x; n]`, `vec![a, b, c, d]`, and `Vec::with_capacity(n)`, will all -/// produce a Vec with exactly the requested capacity. If `len() == capacity()`, -/// (as is the case for the `vec!` macro), then a `Vec` can be converted -/// to and from a `Box<[T]>` without reallocating or moving the elements. +/// `vec![x; n]`, `vec![a, b, c, d]`, and +/// [`Vec::with_capacity(n)`][`Vec::with_capacity`], will all produce a `Vec` +/// with exactly the requested capacity. If [`len()`]` == `[`capacity()`], +/// (as is the case for the [`vec!`] macro), then a `Vec` can be converted to +/// and from a [`Box<[T]>`][owned slice] without reallocating or moving the elements. /// -/// Vec will not specifically overwrite any data that is removed from it, +/// `Vec` will not specifically overwrite any data that is removed from it, /// but also won't specifically preserve it. Its uninitialized memory is /// scratch space that it may use however it wants. It will generally just do /// whatever is most efficient or otherwise easy to implement. Do not rely on -/// removed data to be erased for security purposes. Even if you drop a Vec, its -/// buffer may simply be reused by another Vec. Even if you zero a Vec's memory +/// removed data to be erased for security purposes. Even if you drop a `Vec`, its +/// buffer may simply be reused by another `Vec`. Even if you zero a `Vec`'s memory /// first, that may not actually happen because the optimizer does not consider /// this a side-effect that must be preserved. /// -/// Vec does not currently guarantee the order in which elements are dropped +/// `Vec` does not currently guarantee the order in which elements are dropped /// (the order has changed in the past, and may change again). /// -#[cfg_attr(stage0, unsafe_no_drop_flag)] +/// [`vec!`]: ../../std/macro.vec.html +/// [`Index`]: ../../std/ops/trait.Index.html +/// [`String`]: ../../std/string/struct.String.html +/// [`&str`]: ../../std/primitive.str.html +/// [`Vec::with_capacity`]: ../../std/vec/struct.Vec.html#method.with_capacity +/// [`Vec::new()`]: ../../std/vec/struct.Vec.html#method.new +/// [`shrink_to_fit()`]: ../../std/vec/struct.Vec.html#method.shrink_to_fit +/// [`capacity()`]: ../../std/vec/struct.Vec.html#method.capacity +/// [`mem::size_of::()`]: ../../std/mem/fn.size_of.html +/// [`len()`]: ../../std/vec/struct.Vec.html#method.len +/// [`push`]: ../../std/vec/struct.Vec.html#method.push +/// [`insert`]: ../../std/vec/struct.Vec.html#method.insert +/// [`reserve`]: ../../std/vec/struct.Vec.html#method.reserve +/// [owned slice]: ../../std/boxed/struct.Box.html #[stable(feature = "rust1", since = "1.0.0")] pub struct Vec { buf: RawVec, @@ -305,9 +327,10 @@ impl Vec { /// reallocating. If `capacity` is 0, the vector will not allocate. /// /// It is important to note that this function does not specify the *length* - /// of the returned vector, but only the *capacity*. (For an explanation of - /// the difference between length and capacity, see the main `Vec` docs - /// above, 'Capacity and reallocation'.) + /// of the returned vector, but only the *capacity*. For an explanation of + /// the difference between length and capacity, see *[Capacity and reallocation]*. + /// + /// [Capacity and reallocation]: #capacity-and-reallocation /// /// # Examples /// @@ -341,7 +364,7 @@ impl Vec { /// This is highly unsafe, due to the number of invariants that aren't /// checked: /// - /// * `ptr` needs to have been previously allocated via `String`/`Vec` + /// * `ptr` needs to have been previously allocated via [`String`]/`Vec` /// (at least, it's highly likely to be incorrect if it wasn't). /// * `length` needs to be less than or equal to `capacity`. /// * `capacity` needs to be the capacity that the pointer was allocated with. @@ -355,6 +378,8 @@ impl Vec { /// that nothing else uses the pointer after calling this /// function. /// + /// [`String`]: ../../std/string/struct.String.html + /// /// # Examples /// /// ``` @@ -471,11 +496,15 @@ impl Vec { self.buf.shrink_to_fit(self.len); } - /// Converts the vector into Box<[T]>. + /// Converts the vector into [`Box<[T]>`][owned slice]. /// /// Note that this will drop any excess capacity. Calling this and - /// converting back to a vector with `into_vec()` is equivalent to calling - /// `shrink_to_fit()`. + /// converting back to a vector with [`into_vec()`] is equivalent to calling + /// [`shrink_to_fit()`]. + /// + /// [owned slice]: ../../std/boxed/struct.Box.html + /// [`into_vec()`]: ../../std/primitive.slice.html#method.into_vec + /// [`shrink_to_fit()`]: #method.shrink_to_fit /// /// # Examples /// @@ -674,7 +703,7 @@ impl Vec { /// /// # Panics /// - /// Panics if `index` is greater than the vector's length. + /// Panics if `index` is out of bounds. /// /// # Examples /// @@ -749,7 +778,7 @@ impl Vec { /// Retains only the elements specified by the predicate. /// - /// In other words, remove all elements `e` such that `f(&e)` returns false. + /// In other words, remove all elements `e` such that `f(&e)` returns `false`. /// This method operates in place and preserves the order of the retained /// elements. /// @@ -782,6 +811,130 @@ impl Vec { } } + /// Removes consecutive elements in the vector that resolve to the same key. + /// + /// If the vector is sorted, this removes all duplicates. + /// + /// # Examples + /// + /// ``` + /// #![feature(dedup_by)] + /// + /// let mut vec = vec![10, 20, 21, 30, 20]; + /// + /// vec.dedup_by_key(|i| *i / 10); + /// + /// assert_eq!(vec, [10, 20, 30, 20]); + /// ``` + #[unstable(feature = "dedup_by", reason = "recently added", issue = "37087")] + #[inline] + pub fn dedup_by_key(&mut self, mut key: F) where F: FnMut(&mut T) -> K, K: PartialEq { + self.dedup_by(|a, b| key(a) == key(b)) + } + + /// Removes consecutive elements in the vector that resolve to the same key. + /// + /// If the vector is sorted, this removes all duplicates. + /// + /// # Examples + /// + /// ``` + /// #![feature(dedup_by)] + /// use std::ascii::AsciiExt; + /// + /// let mut vec = vec!["foo", "bar", "Bar", "baz", "bar"]; + /// + /// vec.dedup_by(|a, b| a.eq_ignore_ascii_case(b)); + /// + /// assert_eq!(vec, ["foo", "bar", "baz", "bar"]); + /// ``` + #[unstable(feature = "dedup_by", reason = "recently added", issue = "37087")] + pub fn dedup_by(&mut self, mut same_bucket: F) where F: FnMut(&mut T, &mut T) -> bool { + unsafe { + // Although we have a mutable reference to `self`, we cannot make + // *arbitrary* changes. The `same_bucket` calls could panic, so we + // must ensure that the vector is in a valid state at all time. + // + // The way that we handle this is by using swaps; we iterate + // over all the elements, swapping as we go so that at the end + // the elements we wish to keep are in the front, and those we + // wish to reject are at the back. We can then truncate the + // vector. This operation is still O(n). + // + // Example: We start in this state, where `r` represents "next + // read" and `w` represents "next_write`. + // + // r + // +---+---+---+---+---+---+ + // | 0 | 1 | 1 | 2 | 3 | 3 | + // +---+---+---+---+---+---+ + // w + // + // Comparing self[r] against self[w-1], this is not a duplicate, so + // we swap self[r] and self[w] (no effect as r==w) and then increment both + // r and w, leaving us with: + // + // r + // +---+---+---+---+---+---+ + // | 0 | 1 | 1 | 2 | 3 | 3 | + // +---+---+---+---+---+---+ + // w + // + // Comparing self[r] against self[w-1], this value is a duplicate, + // so we increment `r` but leave everything else unchanged: + // + // r + // +---+---+---+---+---+---+ + // | 0 | 1 | 1 | 2 | 3 | 3 | + // +---+---+---+---+---+---+ + // w + // + // Comparing self[r] against self[w-1], this is not a duplicate, + // so swap self[r] and self[w] and advance r and w: + // + // r + // +---+---+---+---+---+---+ + // | 0 | 1 | 2 | 1 | 3 | 3 | + // +---+---+---+---+---+---+ + // w + // + // Not a duplicate, repeat: + // + // r + // +---+---+---+---+---+---+ + // | 0 | 1 | 2 | 3 | 1 | 3 | + // +---+---+---+---+---+---+ + // w + // + // Duplicate, advance r. End of vec. Truncate to w. + + let ln = self.len(); + if ln <= 1 { + return; + } + + // Avoid bounds checks by using raw pointers. + let p = self.as_mut_ptr(); + let mut r: usize = 1; + let mut w: usize = 1; + + while r < ln { + let p_r = p.offset(r as isize); + let p_wm1 = p.offset((w - 1) as isize); + if !same_bucket(&mut *p_r, &mut *p_wm1) { + if r != w { + let p_w = p_wm1.offset(1); + mem::swap(&mut *p_r, &mut *p_w); + } + w += 1; + } + r += 1; + } + + self.truncate(w); + } + } + /// Appends an element to the back of a collection. /// /// # Panics @@ -810,9 +963,11 @@ impl Vec { } } - /// Removes the last element from a vector and returns it, or `None` if it + /// Removes the last element from a vector and returns it, or [`None`] if it /// is empty. /// + /// [`None`]: ../../std/option/enum.Option.html#variant.None + /// /// # Examples /// /// ``` @@ -1089,26 +1244,7 @@ impl Vec { /// ``` #[stable(feature = "vec_extend_from_slice", since = "1.6.0")] pub fn extend_from_slice(&mut self, other: &[T]) { - self.reserve(other.len()); - - // Unsafe code so this can be optimised to a memcpy (or something - // similarly fast) when T is Copy. LLVM is easily confused, so any - // extra operations during the loop can prevent this optimisation. - unsafe { - let len = self.len(); - let ptr = self.get_unchecked_mut(len) as *mut T; - // Use SetLenOnDrop to work around bug where compiler - // may not realize the store through `ptr` trough self.set_len() - // don't alias. - let mut local_len = SetLenOnDrop::new(&mut self.len); - - for i in 0..other.len() { - ptr::write(ptr.offset(i as isize), other.get_unchecked(i).clone()); - local_len.increment_len(1); - } - - // len set by scope guard - } + self.extend(other.iter().cloned()) } } @@ -1156,90 +1292,9 @@ impl Vec { /// assert_eq!(vec, [1, 2, 3, 2]); /// ``` #[stable(feature = "rust1", since = "1.0.0")] + #[inline] pub fn dedup(&mut self) { - unsafe { - // Although we have a mutable reference to `self`, we cannot make - // *arbitrary* changes. The `PartialEq` comparisons could panic, so we - // must ensure that the vector is in a valid state at all time. - // - // The way that we handle this is by using swaps; we iterate - // over all the elements, swapping as we go so that at the end - // the elements we wish to keep are in the front, and those we - // wish to reject are at the back. We can then truncate the - // vector. This operation is still O(n). - // - // Example: We start in this state, where `r` represents "next - // read" and `w` represents "next_write`. - // - // r - // +---+---+---+---+---+---+ - // | 0 | 1 | 1 | 2 | 3 | 3 | - // +---+---+---+---+---+---+ - // w - // - // Comparing self[r] against self[w-1], this is not a duplicate, so - // we swap self[r] and self[w] (no effect as r==w) and then increment both - // r and w, leaving us with: - // - // r - // +---+---+---+---+---+---+ - // | 0 | 1 | 1 | 2 | 3 | 3 | - // +---+---+---+---+---+---+ - // w - // - // Comparing self[r] against self[w-1], this value is a duplicate, - // so we increment `r` but leave everything else unchanged: - // - // r - // +---+---+---+---+---+---+ - // | 0 | 1 | 1 | 2 | 3 | 3 | - // +---+---+---+---+---+---+ - // w - // - // Comparing self[r] against self[w-1], this is not a duplicate, - // so swap self[r] and self[w] and advance r and w: - // - // r - // +---+---+---+---+---+---+ - // | 0 | 1 | 2 | 1 | 3 | 3 | - // +---+---+---+---+---+---+ - // w - // - // Not a duplicate, repeat: - // - // r - // +---+---+---+---+---+---+ - // | 0 | 1 | 2 | 3 | 1 | 3 | - // +---+---+---+---+---+---+ - // w - // - // Duplicate, advance r. End of vec. Truncate to w. - - let ln = self.len(); - if ln <= 1 { - return; - } - - // Avoid bounds checks by using raw pointers. - let p = self.as_mut_ptr(); - let mut r: usize = 1; - let mut w: usize = 1; - - while r < ln { - let p_r = p.offset(r as isize); - let p_wm1 = p.offset((w - 1) as isize); - if *p_r != *p_wm1 { - if r != w { - let p_w = p_wm1.offset(1); - mem::swap(&mut *p_r, &mut *p_w); - } - w += 1; - } - r += 1; - } - - self.truncate(w); - } + self.dedup_by(|a, b| a == b) } } @@ -1531,19 +1586,25 @@ impl<'a, T> IntoIterator for &'a mut Vec { impl Extend for Vec { #[inline] fn extend>(&mut self, iter: I) { - >::spec_extend(self, iter); - } -} - -impl SpecExtend for Vec { - default fn spec_extend(&mut self, iter: I) { self.extend_desugared(iter.into_iter()) } } -impl SpecExtend> for Vec { - fn spec_extend(&mut self, ref mut other: Vec) { - self.append(other); +trait IsTrustedLen : Iterator { + fn trusted_len(&self) -> Option { None } +} +impl IsTrustedLen for I where I: Iterator { } + +impl IsTrustedLen for I where I: TrustedLen +{ + fn trusted_len(&self) -> Option { + let (low, high) = self.size_hint(); + if let Some(high_value) = high { + debug_assert_eq!(low, high_value, + "TrustedLen iterator's size hint is not exact: {:?}", + (low, high)); + } + high } } @@ -1554,16 +1615,30 @@ impl Vec { // for item in iterator { // self.push(item); // } - while let Some(element) = iterator.next() { - let len = self.len(); - if len == self.capacity() { - let (lower, _) = iterator.size_hint(); - self.reserve(lower.saturating_add(1)); - } + if let Some(additional) = iterator.trusted_len() { + self.reserve(additional); unsafe { - ptr::write(self.get_unchecked_mut(len), element); - // NB can't overflow since we would have had to alloc the address space - self.set_len(len + 1); + let mut ptr = self.as_mut_ptr().offset(self.len() as isize); + let mut local_len = SetLenOnDrop::new(&mut self.len); + for element in iterator { + ptr::write(ptr, element); + ptr = ptr.offset(1); + // NB can't overflow since we would have had to alloc the address space + local_len.increment_len(1); + } + } + } else { + while let Some(element) = iterator.next() { + let len = self.len(); + if len == self.capacity() { + let (lower, _) = iterator.size_hint(); + self.reserve(lower.saturating_add(1)); + } + unsafe { + ptr::write(self.get_unchecked_mut(len), element); + // NB can't overflow since we would have had to alloc the address space + self.set_len(len + 1); + } } } } @@ -1572,7 +1647,7 @@ impl Vec { #[stable(feature = "extend_ref", since = "1.2.0")] impl<'a, T: 'a + Copy> Extend<&'a T> for Vec { fn extend>(&mut self, iter: I) { - self.extend(iter.into_iter().cloned()); + self.extend(iter.into_iter().map(|&x| x)) } } @@ -1705,6 +1780,13 @@ impl<'a, T: Clone> From<&'a [T]> for Vec { } } +#[stable(feature = "vec_from_cow_slice", since = "1.14.0")] +impl<'a, T> From> for Vec where [T]: ToOwned> { + fn from(s: Cow<'a, [T]>) -> Vec { + s.into_owned() + } +} + #[stable(feature = "rust1", since = "1.0.0")] impl<'a> From<&'a str> for Vec { fn from(s: &'a str) -> Vec { @@ -1756,7 +1838,7 @@ pub struct IntoIter { end: *const T, } -#[stable(feature = "vec_intoiter_debug", since = "")] +#[stable(feature = "vec_intoiter_debug", since = "1.13.0")] impl fmt::Debug for IntoIter { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { f.debug_tuple("IntoIter") @@ -1770,7 +1852,7 @@ impl IntoIter { /// /// # Examples /// - /// ```rust + /// ``` /// # #![feature(vec_into_iter_as_slice)] /// let vec = vec!['a', 'b', 'c']; /// let mut into_iter = vec.into_iter(); @@ -1789,7 +1871,7 @@ impl IntoIter { /// /// # Examples /// - /// ```rust + /// ``` /// # #![feature(vec_into_iter_as_slice)] /// let vec = vec!['a', 'b', 'c']; /// let mut into_iter = vec.into_iter(); @@ -1889,6 +1971,9 @@ impl ExactSizeIterator for IntoIter {} #[unstable(feature = "fused", issue = "35602")] impl FusedIterator for IntoIter {} +#[unstable(feature = "trusted_len", issue = "37572")] +unsafe impl TrustedLen for IntoIter {} + #[stable(feature = "vec_into_iter_clone", since = "1.8.0")] impl Clone for IntoIter { fn clone(&self) -> IntoIter { @@ -1930,7 +2015,7 @@ unsafe impl<'a, T: Sync> Sync for Drain<'a, T> {} #[stable(feature = "drain", since = "1.6.0")] unsafe impl<'a, T: Send> Send for Drain<'a, T> {} -#[stable(feature = "rust1", since = "1.0.0")] +#[stable(feature = "drain", since = "1.6.0")] impl<'a, T> Iterator for Drain<'a, T> { type Item = T; @@ -1944,7 +2029,7 @@ impl<'a, T> Iterator for Drain<'a, T> { } } -#[stable(feature = "rust1", since = "1.0.0")] +#[stable(feature = "drain", since = "1.6.0")] impl<'a, T> DoubleEndedIterator for Drain<'a, T> { #[inline] fn next_back(&mut self) -> Option { @@ -1952,7 +2037,7 @@ impl<'a, T> DoubleEndedIterator for Drain<'a, T> { } } -#[stable(feature = "rust1", since = "1.0.0")] +#[stable(feature = "drain", since = "1.6.0")] impl<'a, T> Drop for Drain<'a, T> { fn drop(&mut self) { // exhaust self first @@ -1974,7 +2059,7 @@ impl<'a, T> Drop for Drain<'a, T> { } -#[stable(feature = "rust1", since = "1.0.0")] +#[stable(feature = "drain", since = "1.6.0")] impl<'a, T> ExactSizeIterator for Drain<'a, T> {} #[unstable(feature = "fused", issue = "35602")] diff --git a/src/libcollections/vec_deque.rs b/src/libcollections/vec_deque.rs index 452e9f7482..5397193cab 100644 --- a/src/libcollections/vec_deque.rs +++ b/src/libcollections/vec_deque.rs @@ -743,16 +743,8 @@ impl VecDeque { #[stable(feature = "deque_extras_15", since = "1.5.0")] pub fn as_slices(&self) -> (&[T], &[T]) { unsafe { - let contiguous = self.is_contiguous(); let buf = self.buffer_as_slice(); - if contiguous { - let (empty, buf) = buf.split_at(0); - (&buf[self.tail..self.head], empty) - } else { - let (mid, right) = buf.split_at(self.tail); - let (left, _) = mid.split_at(self.head); - (right, left) - } + RingSlices::ring_slices(buf, self.head, self.tail) } } @@ -780,20 +772,10 @@ impl VecDeque { #[stable(feature = "deque_extras_15", since = "1.5.0")] pub fn as_mut_slices(&mut self) -> (&mut [T], &mut [T]) { unsafe { - let contiguous = self.is_contiguous(); let head = self.head; let tail = self.tail; let buf = self.buffer_as_mut_slice(); - - if contiguous { - let (empty, buf) = buf.split_at_mut(0); - (&mut buf[tail..head], empty) - } else { - let (mid, right) = buf.split_at_mut(tail); - let (left, _) = mid.split_at_mut(head); - - (right, left) - } + RingSlices::ring_slices(buf, head, tail) } } @@ -1829,6 +1811,42 @@ fn wrap_index(index: usize, size: usize) -> usize { index & (size - 1) } +/// Returns the two slices that cover the VecDeque's valid range +trait RingSlices : Sized { + fn slice(self, from: usize, to: usize) -> Self; + fn split_at(self, i: usize) -> (Self, Self); + + fn ring_slices(buf: Self, head: usize, tail: usize) -> (Self, Self) { + let contiguous = tail <= head; + if contiguous { + let (empty, buf) = buf.split_at(0); + (buf.slice(tail, head), empty) + } else { + let (mid, right) = buf.split_at(tail); + let (left, _) = mid.split_at(head); + (right, left) + } + } +} + +impl<'a, T> RingSlices for &'a [T] { + fn slice(self, from: usize, to: usize) -> Self { + &self[from..to] + } + fn split_at(self, i: usize) -> (Self, Self) { + (*self).split_at(i) + } +} + +impl<'a, T> RingSlices for &'a mut [T] { + fn slice(self, from: usize, to: usize) -> Self { + &mut self[from..to] + } + fn split_at(self, i: usize) -> (Self, Self) { + (*self).split_at_mut(i) + } +} + /// Calculate the number of elements left to be read in the buffer #[inline] fn count(tail: usize, head: usize, size: usize) -> usize { @@ -1875,6 +1893,14 @@ impl<'a, T> Iterator for Iter<'a, T> { let len = count(self.tail, self.head, self.ring.len()); (len, Some(len)) } + + fn fold(self, mut accum: Acc, mut f: F) -> Acc + where F: FnMut(Acc, Self::Item) -> Acc, + { + let (front, back) = RingSlices::ring_slices(self.ring, self.head, self.tail); + accum = front.iter().fold(accum, &mut f); + back.iter().fold(accum, &mut f) + } } #[stable(feature = "rust1", since = "1.0.0")] @@ -1927,6 +1953,14 @@ impl<'a, T> Iterator for IterMut<'a, T> { let len = count(self.tail, self.head, self.ring.len()); (len, Some(len)) } + + fn fold(self, mut accum: Acc, mut f: F) -> Acc + where F: FnMut(Acc, Self::Item) -> Acc, + { + let (front, back) = RingSlices::ring_slices(self.ring, self.head, self.tail); + accum = front.iter_mut().fold(accum, &mut f); + back.iter_mut().fold(accum, &mut f) + } } #[stable(feature = "rust1", since = "1.0.0")] @@ -2002,7 +2036,7 @@ unsafe impl<'a, T: Sync> Sync for Drain<'a, T> {} #[stable(feature = "drain", since = "1.6.0")] unsafe impl<'a, T: Send> Send for Drain<'a, T> {} -#[stable(feature = "rust1", since = "1.0.0")] +#[stable(feature = "drain", since = "1.6.0")] impl<'a, T: 'a> Drop for Drain<'a, T> { fn drop(&mut self) { for _ in self.by_ref() {} @@ -2051,7 +2085,7 @@ impl<'a, T: 'a> Drop for Drain<'a, T> { } } -#[stable(feature = "rust1", since = "1.0.0")] +#[stable(feature = "drain", since = "1.6.0")] impl<'a, T: 'a> Iterator for Drain<'a, T> { type Item = T; @@ -2066,7 +2100,7 @@ impl<'a, T: 'a> Iterator for Drain<'a, T> { } } -#[stable(feature = "rust1", since = "1.0.0")] +#[stable(feature = "drain", since = "1.6.0")] impl<'a, T: 'a> DoubleEndedIterator for Drain<'a, T> { #[inline] fn next_back(&mut self) -> Option { @@ -2074,7 +2108,7 @@ impl<'a, T: 'a> DoubleEndedIterator for Drain<'a, T> { } } -#[stable(feature = "rust1", since = "1.0.0")] +#[stable(feature = "drain", since = "1.6.0")] impl<'a, T: 'a> ExactSizeIterator for Drain<'a, T> {} #[unstable(feature = "fused", issue = "35602")] diff --git a/src/libcollectionstest/binary_heap.rs b/src/libcollectionstest/binary_heap.rs index faabcf4c37..9cd63d8793 100644 --- a/src/libcollectionstest/binary_heap.rs +++ b/src/libcollectionstest/binary_heap.rs @@ -299,5 +299,7 @@ fn test_extend_specialization() { #[allow(dead_code)] fn assert_covariance() { - fn drain<'new>(d: Drain<'static, &'static str>) -> Drain<'new, &'new str> { d } + fn drain<'new>(d: Drain<'static, &'static str>) -> Drain<'new, &'new str> { + d + } } diff --git a/src/libcollectionstest/btree/map.rs b/src/libcollectionstest/btree/map.rs index 49fce68d15..8222da105c 100644 --- a/src/libcollectionstest/btree/map.rs +++ b/src/libcollectionstest/btree/map.rs @@ -533,9 +533,7 @@ create_append_test!(test_append_1700, 1700); fn rand_data(len: usize) -> Vec<(u32, u32)> { let mut rng = DeterministicRng::new(); - Vec::from_iter( - (0..len).map(|_| (rng.next(), rng.next())) - ) + Vec::from_iter((0..len).map(|_| (rng.next(), rng.next()))) } #[test] diff --git a/src/libcollectionstest/btree/mod.rs b/src/libcollectionstest/btree/mod.rs index ea43f423b7..ae8b18d0c9 100644 --- a/src/libcollectionstest/btree/mod.rs +++ b/src/libcollectionstest/btree/mod.rs @@ -25,7 +25,7 @@ impl DeterministicRng { x: 0x193a6754, y: 0xa8a7d469, z: 0x97830e05, - w: 0x113ba7bb + w: 0x113ba7bb, } } diff --git a/src/libcollectionstest/btree/set.rs b/src/libcollectionstest/btree/set.rs index a32e3f1a76..6171b8ba62 100644 --- a/src/libcollectionstest/btree/set.rs +++ b/src/libcollectionstest/btree/set.rs @@ -15,45 +15,51 @@ use super::DeterministicRng; #[test] fn test_clone_eq() { - let mut m = BTreeSet::new(); + let mut m = BTreeSet::new(); - m.insert(1); - m.insert(2); + m.insert(1); + m.insert(2); - assert!(m.clone() == m); + assert!(m.clone() == m); } #[test] fn test_hash() { - let mut x = BTreeSet::new(); - let mut y = BTreeSet::new(); + let mut x = BTreeSet::new(); + let mut y = BTreeSet::new(); - x.insert(1); - x.insert(2); - x.insert(3); + x.insert(1); + x.insert(2); + x.insert(3); - y.insert(3); - y.insert(2); - y.insert(1); + y.insert(3); + y.insert(2); + y.insert(1); - assert!(::hash(&x) == ::hash(&y)); + assert!(::hash(&x) == ::hash(&y)); } -fn check(a: &[i32], b: &[i32], expected: &[i32], f: F) where - F: FnOnce(&BTreeSet, &BTreeSet, &mut FnMut(&i32) -> bool) -> bool, +fn check(a: &[i32], b: &[i32], expected: &[i32], f: F) + where F: FnOnce(&BTreeSet, &BTreeSet, &mut FnMut(&i32) -> bool) -> bool { let mut set_a = BTreeSet::new(); let mut set_b = BTreeSet::new(); - for x in a { assert!(set_a.insert(*x)) } - for y in b { assert!(set_b.insert(*y)) } + for x in a { + assert!(set_a.insert(*x)) + } + for y in b { + assert!(set_b.insert(*y)) + } let mut i = 0; - f(&set_a, &set_b, &mut |&x| { - assert_eq!(x, expected[i]); - i += 1; - true - }); + f(&set_a, + &set_b, + &mut |&x| { + assert_eq!(x, expected[i]); + i += 1; + true + }); assert_eq!(i, expected.len()); } @@ -82,9 +88,7 @@ fn test_difference() { check_difference(&[], &[], &[]); check_difference(&[1, 12], &[], &[1, 12]); check_difference(&[], &[1, 2, 3, 9], &[]); - check_difference(&[1, 3, 5, 9, 11], - &[3, 9], - &[1, 5, 11]); + check_difference(&[1, 3, 5, 9, 11], &[3, 9], &[1, 5, 11]); check_difference(&[-5, 11, 22, 33, 40, 42], &[-12, -5, 14, 23, 34, 38, 39, 50], &[11, 22, 33, 40, 42]); @@ -245,10 +249,18 @@ fn test_recovery() { fn test_variance() { use std::collections::btree_set::{IntoIter, Iter, Range}; - fn set<'new>(v: BTreeSet<&'static str>) -> BTreeSet<&'new str> { v } - fn iter<'a, 'new>(v: Iter<'a, &'static str>) -> Iter<'a, &'new str> { v } - fn into_iter<'new>(v: IntoIter<&'static str>) -> IntoIter<&'new str> { v } - fn range<'a, 'new>(v: Range<'a, &'static str>) -> Range<'a, &'new str> { v } + fn set<'new>(v: BTreeSet<&'static str>) -> BTreeSet<&'new str> { + v + } + fn iter<'a, 'new>(v: Iter<'a, &'static str>) -> Iter<'a, &'new str> { + v + } + fn into_iter<'new>(v: IntoIter<&'static str>) -> IntoIter<&'new str> { + v + } + fn range<'a, 'new>(v: Range<'a, &'static str>) -> Range<'a, &'new str> { + v + } } #[test] @@ -277,9 +289,7 @@ fn test_append() { fn rand_data(len: usize) -> Vec { let mut rng = DeterministicRng::new(); - Vec::from_iter( - (0..len).map(|_| rng.next()) - ) + Vec::from_iter((0..len).map(|_| rng.next())) } #[test] diff --git a/src/libcollectionstest/cow_str.rs b/src/libcollectionstest/cow_str.rs new file mode 100644 index 0000000000..b29245121d --- /dev/null +++ b/src/libcollectionstest/cow_str.rs @@ -0,0 +1,141 @@ +// Copyright 2016 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +use std::borrow::Cow; + +// check that Cow<'a, str> implements addition +#[test] +fn check_cow_add_cow() { + let borrowed1 = Cow::Borrowed("Hello, "); + let borrowed2 = Cow::Borrowed("World!"); + let borrow_empty = Cow::Borrowed(""); + + let owned1: Cow = Cow::Owned(String::from("Hi, ")); + let owned2: Cow = Cow::Owned(String::from("Rustaceans!")); + let owned_empty: Cow = Cow::Owned(String::new()); + + assert_eq!("Hello, World!", borrowed1.clone() + borrowed2.clone()); + assert_eq!("Hello, Rustaceans!", borrowed1.clone() + owned2.clone()); + + assert_eq!("Hi, World!", owned1.clone() + borrowed2.clone()); + assert_eq!("Hi, Rustaceans!", owned1.clone() + owned2.clone()); + + if let Cow::Owned(_) = borrowed1.clone() + borrow_empty.clone() { + panic!("Adding empty strings to a borrow should note allocate"); + } + if let Cow::Owned(_) = borrow_empty.clone() + borrowed1.clone() { + panic!("Adding empty strings to a borrow should note allocate"); + } + if let Cow::Owned(_) = borrowed1.clone() + owned_empty.clone() { + panic!("Adding empty strings to a borrow should note allocate"); + } + if let Cow::Owned(_) = owned_empty.clone() + borrowed1.clone() { + panic!("Adding empty strings to a borrow should note allocate"); + } +} + +#[test] +fn check_cow_add_str() { + let borrowed = Cow::Borrowed("Hello, "); + let borrow_empty = Cow::Borrowed(""); + + let owned: Cow = Cow::Owned(String::from("Hi, ")); + let owned_empty: Cow = Cow::Owned(String::new()); + + assert_eq!("Hello, World!", borrowed.clone() + "World!"); + + assert_eq!("Hi, World!", owned.clone() + "World!"); + + if let Cow::Owned(_) = borrowed.clone() + "" { + panic!("Adding empty strings to a borrow should note allocate"); + } + if let Cow::Owned(_) = borrow_empty.clone() + "Hello, " { + panic!("Adding empty strings to a borrow should note allocate"); + } + if let Cow::Owned(_) = owned_empty.clone() + "Hello, " { + panic!("Adding empty strings to a borrow should note allocate"); + } +} + +#[test] +fn check_cow_add_assign_cow() { + let mut borrowed1 = Cow::Borrowed("Hello, "); + let borrowed2 = Cow::Borrowed("World!"); + let borrow_empty = Cow::Borrowed(""); + + let mut owned1: Cow = Cow::Owned(String::from("Hi, ")); + let owned2: Cow = Cow::Owned(String::from("Rustaceans!")); + let owned_empty: Cow = Cow::Owned(String::new()); + + let mut s = borrowed1.clone(); + s += borrow_empty.clone(); + assert_eq!("Hello, ", s); + if let Cow::Owned(_) = s { + panic!("Adding empty strings to a borrow should note allocate"); + } + let mut s = borrow_empty.clone(); + s += borrowed1.clone(); + assert_eq!("Hello, ", s); + if let Cow::Owned(_) = s { + panic!("Adding empty strings to a borrow should note allocate"); + } + let mut s = borrowed1.clone(); + s += owned_empty.clone(); + assert_eq!("Hello, ", s); + if let Cow::Owned(_) = s { + panic!("Adding empty strings to a borrow should note allocate"); + } + let mut s = owned_empty.clone(); + s += borrowed1.clone(); + assert_eq!("Hello, ", s); + if let Cow::Owned(_) = s { + panic!("Adding empty strings to a borrow should note allocate"); + } + + owned1 += borrowed2; + borrowed1 += owned2; + + assert_eq!("Hi, World!", owned1); + assert_eq!("Hello, Rustaceans!", borrowed1); +} + +#[test] +fn check_cow_add_assign_str() { + let mut borrowed = Cow::Borrowed("Hello, "); + let borrow_empty = Cow::Borrowed(""); + + let mut owned: Cow = Cow::Owned(String::from("Hi, ")); + let owned_empty: Cow = Cow::Owned(String::new()); + + let mut s = borrowed.clone(); + s += ""; + assert_eq!("Hello, ", s); + if let Cow::Owned(_) = s { + panic!("Adding empty strings to a borrow should note allocate"); + } + let mut s = borrow_empty.clone(); + s += "World!"; + assert_eq!("World!", s); + if let Cow::Owned(_) = s { + panic!("Adding empty strings to a borrow should note allocate"); + } + let mut s = owned_empty.clone(); + s += "World!"; + assert_eq!("World!", s); + if let Cow::Owned(_) = s { + panic!("Adding empty strings to a borrow should note allocate"); + } + + owned += "World!"; + borrowed += "World!"; + + assert_eq!("Hi, World!", owned); + assert_eq!("Hello, World!", borrowed); +} diff --git a/src/libcollectionstest/lib.rs b/src/libcollectionstest/lib.rs index 950e6ee2e9..14ec8d58be 100644 --- a/src/libcollectionstest/lib.rs +++ b/src/libcollectionstest/lib.rs @@ -16,9 +16,11 @@ #![feature(collections)] #![feature(collections_bound)] #![feature(const_fn)] +#![feature(dedup_by)] #![feature(enumset)] #![feature(pattern)] #![feature(rand)] +#![feature(repeat_str)] #![feature(step_by)] #![feature(str_escape)] #![feature(str_replacen)] @@ -34,10 +36,13 @@ extern crate rustc_unicode; use std::hash::{Hash, Hasher}; use std::collections::hash_map::DefaultHasher; -#[cfg(test)] #[macro_use] mod bench; +#[cfg(test)] +#[macro_use] +mod bench; mod binary_heap; mod btree; +mod cow_str; mod enum_set; mod fmt; mod linked_list; diff --git a/src/libcollectionstest/slice.rs b/src/libcollectionstest/slice.rs index 5b341ab62d..a6230ef471 100644 --- a/src/libcollectionstest/slice.rs +++ b/src/libcollectionstest/slice.rs @@ -315,47 +315,6 @@ fn test_clear() { // If the unsafe block didn't drop things properly, we blow up here. } -#[test] -fn test_dedup() { - fn case(a: Vec, b: Vec) { - let mut v = a; - v.dedup(); - assert_eq!(v, b); - } - case(vec![], vec![]); - case(vec![1], vec![1]); - case(vec![1, 1], vec![1]); - case(vec![1, 2, 3], vec![1, 2, 3]); - case(vec![1, 1, 2, 3], vec![1, 2, 3]); - case(vec![1, 2, 2, 3], vec![1, 2, 3]); - case(vec![1, 2, 3, 3], vec![1, 2, 3]); - case(vec![1, 1, 2, 2, 2, 3, 3], vec![1, 2, 3]); -} - -#[test] -fn test_dedup_unique() { - let mut v0: Vec> = vec![box 1, box 1, box 2, box 3]; - v0.dedup(); - let mut v1: Vec> = vec![box 1, box 2, box 2, box 3]; - v1.dedup(); - let mut v2: Vec> = vec![box 1, box 2, box 3, box 3]; - v2.dedup(); - // If the boxed pointers were leaked or otherwise misused, valgrind - // and/or rt should raise errors. -} - -#[test] -fn test_dedup_shared() { - let mut v0: Vec> = vec![box 1, box 1, box 2, box 3]; - v0.dedup(); - let mut v1: Vec> = vec![box 1, box 2, box 2, box 3]; - v1.dedup(); - let mut v2: Vec> = vec![box 1, box 2, box 3, box 3]; - v2.dedup(); - // If the pointers were leaked or otherwise misused, valgrind and/or - // rt should raise errors. -} - #[test] fn test_retain() { let mut v = vec![1, 2, 3, 4, 5]; @@ -461,12 +420,12 @@ fn test_sort_stability() { // number this element is, i.e. the second elements // will occur in sorted order. let mut v: Vec<_> = (0..len) - .map(|_| { - let n = thread_rng().gen::() % 10; - counts[n] += 1; - (n, counts[n]) - }) - .collect(); + .map(|_| { + let n = thread_rng().gen::() % 10; + counts[n] += 1; + (n, counts[n]) + }) + .collect(); // only sort on the first element, so an unstable sort // may mix up the counts. @@ -1116,6 +1075,7 @@ fn test_box_slice_clone() { } #[test] +#[cfg_attr(target_os = "emscripten", ignore)] fn test_box_slice_clone_panics() { use std::sync::Arc; use std::sync::atomic::{AtomicUsize, Ordering}; @@ -1156,13 +1116,13 @@ fn test_box_slice_clone_panics() { }; spawn(move || { - // When xs is dropped, +5. - let xs = vec![canary.clone(), canary.clone(), canary.clone(), panic, canary] - .into_boxed_slice(); + // When xs is dropped, +5. + let xs = vec![canary.clone(), canary.clone(), canary.clone(), panic, canary] + .into_boxed_slice(); - // When panic is cloned, +3. - xs.clone(); - }) + // When panic is cloned, +3. + xs.clone(); + }) .join() .unwrap_err(); @@ -1414,8 +1374,8 @@ mod bench { let mut rng = thread_rng(); b.iter(|| { let mut v = rng.gen_iter::() - .take(5) - .collect::>(); + .take(5) + .collect::>(); v.sort(); }); b.bytes = 5 * mem::size_of::() as u64; @@ -1426,8 +1386,8 @@ mod bench { let mut rng = thread_rng(); b.iter(|| { let mut v = rng.gen_iter::() - .take(100) - .collect::>(); + .take(100) + .collect::>(); v.sort(); }); b.bytes = 100 * mem::size_of::() as u64; @@ -1438,8 +1398,8 @@ mod bench { let mut rng = thread_rng(); b.iter(|| { let mut v = rng.gen_iter::() - .take(10000) - .collect::>(); + .take(10000) + .collect::>(); v.sort(); }); b.bytes = 10000 * mem::size_of::() as u64; diff --git a/src/libcollectionstest/str.rs b/src/libcollectionstest/str.rs index 62e164a569..cc56bbf489 100644 --- a/src/libcollectionstest/str.rs +++ b/src/libcollectionstest/str.rs @@ -786,9 +786,9 @@ fn test_rev_iterator() { #[test] fn test_chars_decoding() { + let mut bytes = [0; 4]; for c in (0..0x110000).filter_map(::std::char::from_u32) { - let bytes = c.encode_utf8(); - let s = ::std::str::from_utf8(bytes.as_slice()).unwrap(); + let s = c.encode_utf8(&mut bytes); if Some(c) != s.chars().next() { panic!("character {:x}={} does not decode correctly", c as u32, c); } @@ -797,9 +797,9 @@ fn test_chars_decoding() { #[test] fn test_chars_rev_decoding() { + let mut bytes = [0; 4]; for c in (0..0x110000).filter_map(::std::char::from_u32) { - let bytes = c.encode_utf8(); - let s = ::std::str::from_utf8(bytes.as_slice()).unwrap(); + let s = c.encode_utf8(&mut bytes); if Some(c) != s.chars().rev().next() { panic!("character {:x}={} does not decode correctly", c as u32, c); } @@ -1286,6 +1286,13 @@ fn test_cow_from() { } } +#[test] +fn test_repeat() { + assert_eq!("".repeat(3), ""); + assert_eq!("abc".repeat(0), ""); + assert_eq!("α".repeat(3), "ααα"); +} + mod pattern { use std::str::pattern::Pattern; use std::str::pattern::{Searcher, ReverseSearcher}; diff --git a/src/libcollectionstest/string.rs b/src/libcollectionstest/string.rs index 1652fb5a88..98de33bdaa 100644 --- a/src/libcollectionstest/string.rs +++ b/src/libcollectionstest/string.rs @@ -35,6 +35,12 @@ fn test_from_str() { assert_eq!(owned.as_ref().map(|s| &**s), Some("string")); } +#[test] +fn test_from_cow_str() { + assert_eq!(String::from(Cow::Borrowed("string")), "string"); + assert_eq!(String::from(Cow::Owned(String::from("string"))), "string"); +} + #[test] fn test_unsized_to_string() { let s: &str = "abc"; diff --git a/src/libcollectionstest/vec.rs b/src/libcollectionstest/vec.rs index ee2b898d5c..3bc1321d75 100644 --- a/src/libcollectionstest/vec.rs +++ b/src/libcollectionstest/vec.rs @@ -8,6 +8,7 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. +use std::ascii::AsciiExt; use std::borrow::Cow; use std::iter::{FromIterator, repeat}; use std::mem::size_of; @@ -213,6 +214,60 @@ fn test_retain() { assert_eq!(vec, [2, 4]); } +#[test] +fn test_dedup() { + fn case(a: Vec, b: Vec) { + let mut v = a; + v.dedup(); + assert_eq!(v, b); + } + case(vec![], vec![]); + case(vec![1], vec![1]); + case(vec![1, 1], vec![1]); + case(vec![1, 2, 3], vec![1, 2, 3]); + case(vec![1, 1, 2, 3], vec![1, 2, 3]); + case(vec![1, 2, 2, 3], vec![1, 2, 3]); + case(vec![1, 2, 3, 3], vec![1, 2, 3]); + case(vec![1, 1, 2, 2, 2, 3, 3], vec![1, 2, 3]); +} + +#[test] +fn test_dedup_by_key() { + fn case(a: Vec, b: Vec) { + let mut v = a; + v.dedup_by_key(|i| *i / 10); + assert_eq!(v, b); + } + case(vec![], vec![]); + case(vec![10], vec![10]); + case(vec![10, 11], vec![10]); + case(vec![10, 20, 30], vec![10, 20, 30]); + case(vec![10, 11, 20, 30], vec![10, 20, 30]); + case(vec![10, 20, 21, 30], vec![10, 20, 30]); + case(vec![10, 20, 30, 31], vec![10, 20, 30]); + case(vec![10, 11, 20, 21, 22, 30, 31], vec![10, 20, 30]); +} + +#[test] +fn test_dedup_by() { + let mut vec = vec!["foo", "bar", "Bar", "baz", "bar"]; + vec.dedup_by(|a, b| a.eq_ignore_ascii_case(b)); + + assert_eq!(vec, ["foo", "bar", "baz", "bar"]); +} + +#[test] +fn test_dedup_unique() { + let mut v0: Vec> = vec![box 1, box 1, box 2, box 3]; + v0.dedup(); + let mut v1: Vec> = vec![box 1, box 2, box 2, box 3]; + v1.dedup(); + let mut v2: Vec> = vec![box 1, box 2, box 3, box 3]; + v2.dedup(); + // If the boxed pointers were leaked or otherwise misused, valgrind + // and/or rt should raise errors. +} + #[test] fn zero_sized_values() { let mut v = Vec::new(); @@ -271,22 +326,22 @@ fn test_zip_unzip() { #[test] fn test_vec_truncate_drop() { - static mut drops: u32 = 0; + static mut DROPS: u32 = 0; struct Elem(i32); impl Drop for Elem { fn drop(&mut self) { unsafe { - drops += 1; + DROPS += 1; } } } let mut v = vec![Elem(1), Elem(2), Elem(3), Elem(4), Elem(5)]; - assert_eq!(unsafe { drops }, 0); + assert_eq!(unsafe { DROPS }, 0); v.truncate(3); - assert_eq!(unsafe { drops }, 2); + assert_eq!(unsafe { DROPS }, 2); v.truncate(0); - assert_eq!(unsafe { drops }, 5); + assert_eq!(unsafe { DROPS }, 5); } #[test] @@ -542,10 +597,22 @@ fn test_cow_from() { } } +#[test] +fn test_from_cow() { + let borrowed: &[_] = &["borrowed", "(slice)"]; + let owned = vec!["owned", "(vec)"]; + assert_eq!(Vec::from(Cow::Borrowed(borrowed)), vec!["borrowed", "(slice)"]); + assert_eq!(Vec::from(Cow::Owned(owned)), vec!["owned", "(vec)"]); +} + #[allow(dead_code)] fn assert_covariance() { - fn drain<'new>(d: Drain<'static, &'static str>) -> Drain<'new, &'new str> { d } - fn into_iter<'new>(i: IntoIter<&'static str>) -> IntoIter<&'new str> { i } + fn drain<'new>(d: Drain<'static, &'static str>) -> Drain<'new, &'new str> { + d + } + fn into_iter<'new>(i: IntoIter<&'static str>) -> IntoIter<&'new str> { + i + } } #[bench] diff --git a/src/libcollectionstest/vec_deque.rs b/src/libcollectionstest/vec_deque.rs index 5e8633a974..f1ea85a6c5 100644 --- a/src/libcollectionstest/vec_deque.rs +++ b/src/libcollectionstest/vec_deque.rs @@ -686,21 +686,21 @@ fn test_show() { assert_eq!(format!("{:?}", ringbuf), "[0, 1, 2, 3, 4, 5, 6, 7, 8, 9]"); let ringbuf: VecDeque<_> = vec!["just", "one", "test", "more"] - .iter() - .cloned() - .collect(); + .iter() + .cloned() + .collect(); assert_eq!(format!("{:?}", ringbuf), "[\"just\", \"one\", \"test\", \"more\"]"); } #[test] fn test_drop() { - static mut drops: i32 = 0; + static mut DROPS: i32 = 0; struct Elem; impl Drop for Elem { fn drop(&mut self) { unsafe { - drops += 1; + DROPS += 1; } } } @@ -712,17 +712,17 @@ fn test_drop() { ring.push_front(Elem); drop(ring); - assert_eq!(unsafe { drops }, 4); + assert_eq!(unsafe { DROPS }, 4); } #[test] fn test_drop_with_pop() { - static mut drops: i32 = 0; + static mut DROPS: i32 = 0; struct Elem; impl Drop for Elem { fn drop(&mut self) { unsafe { - drops += 1; + DROPS += 1; } } } @@ -735,20 +735,20 @@ fn test_drop_with_pop() { drop(ring.pop_back()); drop(ring.pop_front()); - assert_eq!(unsafe { drops }, 2); + assert_eq!(unsafe { DROPS }, 2); drop(ring); - assert_eq!(unsafe { drops }, 4); + assert_eq!(unsafe { DROPS }, 4); } #[test] fn test_drop_clear() { - static mut drops: i32 = 0; + static mut DROPS: i32 = 0; struct Elem; impl Drop for Elem { fn drop(&mut self) { unsafe { - drops += 1; + DROPS += 1; } } } @@ -759,10 +759,10 @@ fn test_drop_clear() { ring.push_back(Elem); ring.push_front(Elem); ring.clear(); - assert_eq!(unsafe { drops }, 4); + assert_eq!(unsafe { DROPS }, 4); drop(ring); - assert_eq!(unsafe { drops }, 4); + assert_eq!(unsafe { DROPS }, 4); } #[test] @@ -1003,5 +1003,7 @@ fn test_contains() { #[allow(dead_code)] fn assert_covariance() { - fn drain<'new>(d: Drain<'static, &'static str>) -> Drain<'new, &'new str> { d } + fn drain<'new>(d: Drain<'static, &'static str>) -> Drain<'new, &'new str> { + d + } } diff --git a/src/libcompiler_builtins/build.rs b/src/libcompiler_builtins/build.rs index 66c683333b..acbd39bb16 100644 --- a/src/libcompiler_builtins/build.rs +++ b/src/libcompiler_builtins/build.rs @@ -73,6 +73,12 @@ impl Sources { fn main() { let target = env::var("TARGET").expect("TARGET was not set"); + + // Emscripten's runtime includes all the builtins + if target.contains("emscripten") { + return; + } + let cfg = &mut gcc::Config::new(); if target.contains("msvc") { diff --git a/src/libcompiler_builtins/lib.rs b/src/libcompiler_builtins/lib.rs index fbcf5204d2..4a703b3da6 100644 --- a/src/libcompiler_builtins/lib.rs +++ b/src/libcompiler_builtins/lib.rs @@ -8,9 +8,9 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -#![cfg_attr(not(stage0), feature(compiler_builtins))] +#![feature(compiler_builtins)] #![no_std] -#![cfg_attr(not(stage0), compiler_builtins)] +#![compiler_builtins] #![unstable(feature = "compiler_builtins_lib", reason = "internal implementation detail of rustc right now", issue = "0")] diff --git a/src/libcore/any.rs b/src/libcore/any.rs index f7edcb998a..eb0636e857 100644 --- a/src/libcore/any.rs +++ b/src/libcore/any.rs @@ -351,12 +351,10 @@ impl TypeId { /// # Examples /// /// ``` - /// #![feature(get_type_id)] - /// /// use std::any::{Any, TypeId}; /// - /// fn is_string(s: &Any) -> bool { - /// TypeId::of::() == s.get_type_id() + /// fn is_string(_s: &T) -> bool { + /// TypeId::of::() == TypeId::of::() /// } /// /// fn main() { diff --git a/src/libcore/array.rs b/src/libcore/array.rs index 9866a39619..37bd57034a 100644 --- a/src/libcore/array.rs +++ b/src/libcore/array.rs @@ -93,6 +93,7 @@ macro_rules! __impl_slice_eq2 { macro_rules! array_impls { ($($N:expr)+) => { $( + #[stable(feature = "rust1", since = "1.0.0")] impl AsRef<[T]> for [T; $N] { #[inline] fn as_ref(&self) -> &[T] { @@ -100,6 +101,7 @@ macro_rules! array_impls { } } + #[stable(feature = "rust1", since = "1.0.0")] impl AsMut<[T]> for [T; $N] { #[inline] fn as_mut(&mut self) -> &mut [T] { diff --git a/src/libcore/char.rs b/src/libcore/char.rs index a21d1229d3..26d28049a4 100644 --- a/src/libcore/char.rs +++ b/src/libcore/char.rs @@ -18,6 +18,7 @@ use char_private::is_printable; use convert::TryFrom; use fmt; +use slice; use iter::FusedIterator; use mem::transmute; @@ -327,9 +328,9 @@ pub trait CharExt { #[stable(feature = "core", since = "1.6.0")] fn len_utf16(self) -> usize; #[unstable(feature = "unicode", issue = "27784")] - fn encode_utf8(self) -> EncodeUtf8; + fn encode_utf8(self, dst: &mut [u8]) -> &mut str; #[unstable(feature = "unicode", issue = "27784")] - fn encode_utf16(self) -> EncodeUtf16; + fn encode_utf16(self, dst: &mut [u16]) -> &mut [u16]; } #[stable(feature = "core", since = "1.6.0")] @@ -419,47 +420,59 @@ impl CharExt for char { } #[inline] - fn encode_utf8(self) -> EncodeUtf8 { + fn encode_utf8(self, dst: &mut [u8]) -> &mut str { let code = self as u32; - let mut buf = [0; 4]; - let pos = if code < MAX_ONE_B { - buf[3] = code as u8; - 3 - } else if code < MAX_TWO_B { - buf[2] = (code >> 6 & 0x1F) as u8 | TAG_TWO_B; - buf[3] = (code & 0x3F) as u8 | TAG_CONT; - 2 - } else if code < MAX_THREE_B { - buf[1] = (code >> 12 & 0x0F) as u8 | TAG_THREE_B; - buf[2] = (code >> 6 & 0x3F) as u8 | TAG_CONT; - buf[3] = (code & 0x3F) as u8 | TAG_CONT; - 1 - } else { - buf[0] = (code >> 18 & 0x07) as u8 | TAG_FOUR_B; - buf[1] = (code >> 12 & 0x3F) as u8 | TAG_CONT; - buf[2] = (code >> 6 & 0x3F) as u8 | TAG_CONT; - buf[3] = (code & 0x3F) as u8 | TAG_CONT; - 0 - }; - EncodeUtf8 { buf: buf, pos: pos } + unsafe { + let len = + if code < MAX_ONE_B && !dst.is_empty() { + *dst.get_unchecked_mut(0) = code as u8; + 1 + } else if code < MAX_TWO_B && dst.len() >= 2 { + *dst.get_unchecked_mut(0) = (code >> 6 & 0x1F) as u8 | TAG_TWO_B; + *dst.get_unchecked_mut(1) = (code & 0x3F) as u8 | TAG_CONT; + 2 + } else if code < MAX_THREE_B && dst.len() >= 3 { + *dst.get_unchecked_mut(0) = (code >> 12 & 0x0F) as u8 | TAG_THREE_B; + *dst.get_unchecked_mut(1) = (code >> 6 & 0x3F) as u8 | TAG_CONT; + *dst.get_unchecked_mut(2) = (code & 0x3F) as u8 | TAG_CONT; + 3 + } else if dst.len() >= 4 { + *dst.get_unchecked_mut(0) = (code >> 18 & 0x07) as u8 | TAG_FOUR_B; + *dst.get_unchecked_mut(1) = (code >> 12 & 0x3F) as u8 | TAG_CONT; + *dst.get_unchecked_mut(2) = (code >> 6 & 0x3F) as u8 | TAG_CONT; + *dst.get_unchecked_mut(3) = (code & 0x3F) as u8 | TAG_CONT; + 4 + } else { + panic!("encode_utf8: need {} bytes to encode U+{:X}, but the buffer has {}", + from_u32_unchecked(code).len_utf8(), + code, + dst.len()) + }; + transmute(slice::from_raw_parts_mut(dst.as_mut_ptr(), len)) + } } #[inline] - fn encode_utf16(self) -> EncodeUtf16 { - let mut buf = [0; 2]; + fn encode_utf16(self, dst: &mut [u16]) -> &mut [u16] { let mut code = self as u32; - let pos = if (code & 0xFFFF) == code { - // The BMP falls through (assuming non-surrogate, as it should) - buf[1] = code as u16; - 1 - } else { - // Supplementary planes break into surrogates. - code -= 0x1_0000; - buf[0] = 0xD800 | ((code >> 10) as u16); - buf[1] = 0xDC00 | ((code as u16) & 0x3FF); - 0 - }; - EncodeUtf16 { buf: buf, pos: pos } + unsafe { + if (code & 0xFFFF) == code && !dst.is_empty() { + // The BMP falls through (assuming non-surrogate, as it should) + *dst.get_unchecked_mut(0) = code as u16; + slice::from_raw_parts_mut(dst.as_mut_ptr(), 1) + } else if dst.len() >= 2 { + // Supplementary planes break into surrogates. + code -= 0x1_0000; + *dst.get_unchecked_mut(0) = 0xD800 | ((code >> 10) as u16); + *dst.get_unchecked_mut(1) = 0xDC00 | ((code as u16) & 0x3FF); + slice::from_raw_parts_mut(dst.as_mut_ptr(), 2) + } else { + panic!("encode_utf16: need {} units to encode U+{:X}, but the buffer has {}", + from_u32_unchecked(code).len_utf16(), + code, + dst.len()) + } + } } } @@ -702,88 +715,7 @@ impl ExactSizeIterator for EscapeDebug { } #[unstable(feature = "fused", issue = "35602")] impl FusedIterator for EscapeDebug {} -/// An iterator over `u8` entries represending the UTF-8 encoding of a `char` -/// value. -/// -/// Constructed via the `.encode_utf8()` method on `char`. -#[unstable(feature = "unicode", issue = "27784")] -#[derive(Debug)] -pub struct EncodeUtf8 { - buf: [u8; 4], - pos: usize, -} - -impl EncodeUtf8 { - /// Returns the remaining bytes of this iterator as a slice. - #[unstable(feature = "unicode", issue = "27784")] - pub fn as_slice(&self) -> &[u8] { - &self.buf[self.pos..] - } -} - -#[unstable(feature = "unicode", issue = "27784")] -impl Iterator for EncodeUtf8 { - type Item = u8; - - fn next(&mut self) -> Option { - if self.pos == self.buf.len() { - None - } else { - let ret = Some(self.buf[self.pos]); - self.pos += 1; - ret - } - } - - fn size_hint(&self) -> (usize, Option) { - self.as_slice().iter().size_hint() - } -} - -#[unstable(feature = "fused", issue = "35602")] -impl FusedIterator for EncodeUtf8 {} - -/// An iterator over `u16` entries represending the UTF-16 encoding of a `char` -/// value. -/// -/// Constructed via the `.encode_utf16()` method on `char`. -#[unstable(feature = "unicode", issue = "27784")] -#[derive(Debug)] -pub struct EncodeUtf16 { - buf: [u16; 2], - pos: usize, -} - -impl EncodeUtf16 { - /// Returns the remaining bytes of this iterator as a slice. - #[unstable(feature = "unicode", issue = "27784")] - pub fn as_slice(&self) -> &[u16] { - &self.buf[self.pos..] - } -} - - -#[unstable(feature = "unicode", issue = "27784")] -impl Iterator for EncodeUtf16 { - type Item = u16; - - fn next(&mut self) -> Option { - if self.pos == self.buf.len() { - None - } else { - let ret = Some(self.buf[self.pos]); - self.pos += 1; - ret - } - } - - fn size_hint(&self) -> (usize, Option) { - self.as_slice().iter().size_hint() - } -} -#[unstable(feature = "fused", issue = "35602")] -impl FusedIterator for EncodeUtf16 {} /// An iterator over an iterator of bytes of the characters the bytes represent /// as UTF-8 diff --git a/src/libcore/clone.rs b/src/libcore/clone.rs index 0b800cacfc..d72b18ae34 100644 --- a/src/libcore/clone.rs +++ b/src/libcore/clone.rs @@ -129,13 +129,6 @@ pub struct AssertParamIsClone { _field: ::marker::PhantomData reason = "deriving hack, should not be public", issue = "0")] pub struct AssertParamIsCopy { _field: ::marker::PhantomData } -#[cfg(stage0)] -#[doc(hidden)] -#[inline(always)] -#[unstable(feature = "derive_clone_copy", - reason = "deriving hack, should not be public", - issue = "0")] -pub fn assert_receiver_is_clone(_: &T) {} #[stable(feature = "rust1", since = "1.0.0")] impl<'a, T: ?Sized> Clone for &'a T { diff --git a/src/libcore/cmp.rs b/src/libcore/cmp.rs index f990a27e52..0daf658a0f 100644 --- a/src/libcore/cmp.rs +++ b/src/libcore/cmp.rs @@ -10,10 +10,13 @@ //! Functionality for ordering and comparison. //! -//! This module defines both `PartialOrd` and `PartialEq` traits which are used +//! This module defines both [`PartialOrd`] and [`PartialEq`] traits which are used //! by the compiler to implement comparison operators. Rust programs may -//! implement `PartialOrd` to overload the `<`, `<=`, `>`, and `>=` operators, -//! and may implement `PartialEq` to overload the `==` and `!=` operators. +//! implement [`PartialOrd`] to overload the `<`, `<=`, `>`, and `>=` operators, +//! and may implement [`PartialEq`] to overload the `==` and `!=` operators. +//! +//! [`PartialOrd`]: trait.PartialOrd.html +//! [`PartialEq`]: trait.PartialEq.html //! //! # Examples //! @@ -245,6 +248,80 @@ impl Ordering { Greater => Less, } } + + /// Chains two orderings. + /// + /// Returns `self` when it's not `Equal`. Otherwise returns `other`. + /// # Examples + /// + /// ``` + /// #![feature(ordering_chaining)] + /// + /// use std::cmp::Ordering; + /// + /// let result = Ordering::Equal.then(Ordering::Less); + /// assert_eq!(result, Ordering::Less); + /// + /// let result = Ordering::Less.then(Ordering::Equal); + /// assert_eq!(result, Ordering::Less); + /// + /// let result = Ordering::Less.then(Ordering::Greater); + /// assert_eq!(result, Ordering::Less); + /// + /// let result = Ordering::Equal.then(Ordering::Equal); + /// assert_eq!(result, Ordering::Equal); + /// + /// let x: (i64, i64, i64) = (1, 2, 7); + /// let y: (i64, i64, i64) = (1, 5, 3); + /// let result = x.0.cmp(&y.0).then(x.1.cmp(&y.1)).then(x.2.cmp(&y.2)); + /// + /// assert_eq!(result, Ordering::Less); + /// ``` + #[unstable(feature = "ordering_chaining", issue = "37053")] + pub fn then(self, other: Ordering) -> Ordering { + match self { + Equal => other, + _ => self, + } + } + + /// Chains the ordering with the given function. + /// + /// Returns `self` when it's not `Equal`. Otherwise calls `f` and returns + /// the result. + /// + /// # Examples + /// + /// ``` + /// #![feature(ordering_chaining)] + /// + /// use std::cmp::Ordering; + /// + /// let result = Ordering::Equal.then_with(|| Ordering::Less); + /// assert_eq!(result, Ordering::Less); + /// + /// let result = Ordering::Less.then_with(|| Ordering::Equal); + /// assert_eq!(result, Ordering::Less); + /// + /// let result = Ordering::Less.then_with(|| Ordering::Greater); + /// assert_eq!(result, Ordering::Less); + /// + /// let result = Ordering::Equal.then_with(|| Ordering::Equal); + /// assert_eq!(result, Ordering::Equal); + /// + /// let x: (i64, i64, i64) = (1, 2, 7); + /// let y: (i64, i64, i64) = (1, 5, 3); + /// let result = x.0.cmp(&y.0).then_with(|| x.1.cmp(&y.1)).then_with(|| x.2.cmp(&y.2)); + /// + /// assert_eq!(result, Ordering::Less); + /// ``` + #[unstable(feature = "ordering_chaining", issue = "37053")] + pub fn then_with Ordering>(self, f: F) -> Ordering { + match self { + Equal => f(), + _ => self, + } + } } /// Trait for types that form a [total order](https://en.wikipedia.org/wiki/Total_order). @@ -703,24 +780,24 @@ mod impls { ord_impl! { char usize u8 u16 u32 u64 isize i8 i16 i32 i64 } - #[unstable(feature = "never_type", issue = "35121")] + #[unstable(feature = "never_type_impls", issue = "35121")] impl PartialEq for ! { fn eq(&self, _: &!) -> bool { *self } } - #[unstable(feature = "never_type", issue = "35121")] + #[unstable(feature = "never_type_impls", issue = "35121")] impl Eq for ! {} - #[unstable(feature = "never_type", issue = "35121")] + #[unstable(feature = "never_type_impls", issue = "35121")] impl PartialOrd for ! { fn partial_cmp(&self, _: &!) -> Option { *self } } - #[unstable(feature = "never_type", issue = "35121")] + #[unstable(feature = "never_type_impls", issue = "35121")] impl Ord for ! { fn cmp(&self, _: &!) -> Ordering { *self diff --git a/src/libcore/convert.rs b/src/libcore/convert.rs index 5f16a4f243..830bbc079a 100644 --- a/src/libcore/convert.rs +++ b/src/libcore/convert.rs @@ -145,7 +145,7 @@ pub trait AsMut { /// /// # Generic Impls /// -/// - `[From][From] for U` implies `Into for T` +/// - [`From`][From]` for U` implies `Into for T` /// - [`into()`] is reflexive, which means that `Into for T` is implemented /// /// [`TryInto`]: trait.TryInto.html @@ -178,14 +178,14 @@ pub trait Into: Sized { /// ``` /// # Generic impls /// -/// - `From for U` implies `[Into] for T` +/// - `From for U` implies [`Into`]` for T` /// - [`from()`] is reflexive, which means that `From for T` is implemented /// /// [`TryFrom`]: trait.TryFrom.html /// [`Option`]: ../../std/option/enum.Option.html /// [`Result`]: ../../std/result/enum.Result.html /// [`String`]: ../../std/string/struct.String.html -/// [Into]: trait.Into.html +/// [`Into`]: trait.Into.html /// [`from()`]: trait.From.html#tymethod.from #[stable(feature = "rust1", since = "1.0.0")] pub trait From: Sized { diff --git a/src/libcore/fmt/mod.rs b/src/libcore/fmt/mod.rs index 8342d663cd..2d75a8ec42 100644 --- a/src/libcore/fmt/mod.rs +++ b/src/libcore/fmt/mod.rs @@ -97,9 +97,7 @@ pub trait Write { /// This function will return an instance of `Error` on error. #[stable(feature = "fmt_write_char", since = "1.1.0")] fn write_char(&mut self, c: char) -> Result { - self.write_str(unsafe { - str::from_utf8_unchecked(c.encode_utf8().as_slice()) - }) + self.write_str(c.encode_utf8(&mut [0; 4])) } /// Glue for usage of the `write!` macro with implementors of this trait. @@ -796,7 +794,7 @@ pub trait UpperExp { /// assert_eq!(output, "Hello world!"); /// ``` /// -/// Please note that using [`write!`][write_macro] might be preferrable. Example: +/// Please note that using [`write!`] might be preferrable. Example: /// /// ``` /// use std::fmt::Write; @@ -807,7 +805,7 @@ pub trait UpperExp { /// assert_eq!(output, "Hello world!"); /// ``` /// -/// [write_macro]: ../../std/macro.write!.html +/// [`write!`]: ../../std/macro.write.html #[stable(feature = "rust1", since = "1.0.0")] pub fn write(output: &mut Write, args: Arguments) -> Result { let mut formatter = Formatter { @@ -924,9 +922,7 @@ impl<'a> Formatter<'a> { // Writes the sign if it exists, and then the prefix if it was requested let write_prefix = |f: &mut Formatter| { if let Some(c) = sign { - f.buf.write_str(unsafe { - str::from_utf8_unchecked(c.encode_utf8().as_slice()) - })?; + f.buf.write_str(c.encode_utf8(&mut [0; 4]))?; } if prefixed { f.buf.write_str(prefix) } else { Ok(()) } @@ -1032,10 +1028,8 @@ impl<'a> Formatter<'a> { rt::v1::Alignment::Center => (padding / 2, (padding + 1) / 2), }; - let fill = self.fill.encode_utf8(); - let fill = unsafe { - str::from_utf8_unchecked(fill.as_slice()) - }; + let mut fill = [0; 4]; + let fill = self.fill.encode_utf8(&mut fill); for _ in 0..pre_pad { self.buf.write_str(fill)?; @@ -1362,14 +1356,14 @@ macro_rules! fmt_refs { fmt_refs! { Debug, Display, Octal, Binary, LowerHex, UpperHex, LowerExp, UpperExp } -#[unstable(feature = "never_type", issue = "35121")] +#[unstable(feature = "never_type_impls", issue = "35121")] impl Debug for ! { fn fmt(&self, _: &mut Formatter) -> Result { *self } } -#[unstable(feature = "never_type", issue = "35121")] +#[unstable(feature = "never_type_impls", issue = "35121")] impl Display for ! { fn fmt(&self, _: &mut Formatter) -> Result { *self @@ -1435,9 +1429,7 @@ impl Display for char { if f.width.is_none() && f.precision.is_none() { f.write_char(*self) } else { - f.pad(unsafe { - str::from_utf8_unchecked(self.encode_utf8().as_slice()) - }) + f.pad(self.encode_utf8(&mut [0; 4])) } } } @@ -1574,11 +1566,11 @@ floating! { f64 } // Implementation of Display/Debug for various core types #[stable(feature = "rust1", since = "1.0.0")] -impl Debug for *const T { +impl Debug for *const T { fn fmt(&self, f: &mut Formatter) -> Result { Pointer::fmt(self, f) } } #[stable(feature = "rust1", since = "1.0.0")] -impl Debug for *mut T { +impl Debug for *mut T { fn fmt(&self, f: &mut Formatter) -> Result { Pointer::fmt(self, f) } } diff --git a/src/libcore/hash/mod.rs b/src/libcore/hash/mod.rs index 6a60cfcc12..ac36cbaace 100644 --- a/src/libcore/hash/mod.rs +++ b/src/libcore/hash/mod.rs @@ -38,7 +38,9 @@ //! ``` //! //! If you need more control over how a value is hashed, you need to implement -//! the `Hash` trait: +//! the [`Hash`] trait: +//! +//! [`Hash`]: trait.Hash.html //! //! ```rust //! use std::hash::{Hash, Hasher, SipHasher}; @@ -90,7 +92,7 @@ mod sip; /// The `H` type parameter is an abstract hash state that is used by the `Hash` /// to compute the hash. /// -/// If you are also implementing `Eq`, there is an additional property that +/// If you are also implementing [`Eq`], there is an additional property that /// is important: /// /// ```text @@ -98,13 +100,13 @@ mod sip; /// ``` /// /// In other words, if two keys are equal, their hashes should also be equal. -/// `HashMap` and `HashSet` both rely on this behavior. +/// [`HashMap`] and [`HashSet`] both rely on this behavior. /// /// ## Derivable /// /// This trait can be used with `#[derive]` if all fields implement `Hash`. /// When `derive`d, the resulting hash will be the combination of the values -/// from calling `.hash()` on each field. +/// from calling [`.hash()`] on each field. /// /// ## How can I implement `Hash`? /// @@ -127,6 +129,11 @@ mod sip; /// } /// } /// ``` +/// +/// [`Eq`]: ../../std/cmp/trait.Eq.html +/// [`HashMap`]: ../../std/collections/struct.HashMap.html +/// [`HashSet`]: ../../std/collections/struct.HashSet.html +/// [`.hash()`]: #tymethod.hash #[stable(feature = "rust1", since = "1.0.0")] pub trait Hash { /// Feeds this value into the state given, updating the hasher as necessary. @@ -151,35 +158,35 @@ pub trait Hasher { #[stable(feature = "rust1", since = "1.0.0")] fn finish(&self) -> u64; - /// Writes some data into this `Hasher` + /// Writes some data into this `Hasher`. #[stable(feature = "rust1", since = "1.0.0")] fn write(&mut self, bytes: &[u8]); - /// Write a single `u8` into this hasher + /// Write a single `u8` into this hasher. #[inline] #[stable(feature = "hasher_write", since = "1.3.0")] fn write_u8(&mut self, i: u8) { self.write(&[i]) } - /// Write a single `u16` into this hasher. + /// Writes a single `u16` into this hasher. #[inline] #[stable(feature = "hasher_write", since = "1.3.0")] fn write_u16(&mut self, i: u16) { self.write(&unsafe { mem::transmute::<_, [u8; 2]>(i) }) } - /// Write a single `u32` into this hasher. + /// Writes a single `u32` into this hasher. #[inline] #[stable(feature = "hasher_write", since = "1.3.0")] fn write_u32(&mut self, i: u32) { self.write(&unsafe { mem::transmute::<_, [u8; 4]>(i) }) } - /// Write a single `u64` into this hasher. + /// Writes a single `u64` into this hasher. #[inline] #[stable(feature = "hasher_write", since = "1.3.0")] fn write_u64(&mut self, i: u64) { self.write(&unsafe { mem::transmute::<_, [u8; 8]>(i) }) } - /// Write a single `usize` into this hasher. + /// Writes a single `usize` into this hasher. #[inline] #[stable(feature = "hasher_write", since = "1.3.0")] fn write_usize(&mut self, i: usize) { @@ -189,31 +196,31 @@ pub trait Hasher { self.write(bytes); } - /// Write a single `i8` into this hasher. + /// Writes a single `i8` into this hasher. #[inline] #[stable(feature = "hasher_write", since = "1.3.0")] fn write_i8(&mut self, i: i8) { self.write_u8(i as u8) } - /// Write a single `i16` into this hasher. + /// Writes a single `i16` into this hasher. #[inline] #[stable(feature = "hasher_write", since = "1.3.0")] fn write_i16(&mut self, i: i16) { self.write_u16(i as u16) } - /// Write a single `i32` into this hasher. + /// Writes a single `i32` into this hasher. #[inline] #[stable(feature = "hasher_write", since = "1.3.0")] fn write_i32(&mut self, i: i32) { self.write_u32(i as u32) } - /// Write a single `i64` into this hasher. + /// Writes a single `i64` into this hasher. #[inline] #[stable(feature = "hasher_write", since = "1.3.0")] fn write_i64(&mut self, i: i64) { self.write_u64(i as u64) } - /// Write a single `isize` into this hasher. + /// Writes a single `isize` into this hasher. #[inline] #[stable(feature = "hasher_write", since = "1.3.0")] fn write_isize(&mut self, i: isize) { diff --git a/src/libcore/hash/sip.rs b/src/libcore/hash/sip.rs index bf138a45de..5f5d07b668 100644 --- a/src/libcore/hash/sip.rs +++ b/src/libcore/hash/sip.rs @@ -14,12 +14,18 @@ use marker::PhantomData; use ptr; +use cmp; +use mem; /// An implementation of SipHash 1-3. /// +/// This is currently the default hashing function used by standard library +/// (eg. `collections::HashMap` uses it by default). +/// /// See: https://131002.net/siphash/ #[unstable(feature = "sip_hash_13", issue = "34767")] -#[rustc_deprecated(since = "1.13.0", reason = "use `DefaultHasher` instead")] +#[rustc_deprecated(since = "1.13.0", + reason = "use `std::collections::hash_map::DefaultHasher` instead")] #[derive(Debug, Clone, Default)] pub struct SipHasher13 { hasher: Hasher, @@ -29,7 +35,8 @@ pub struct SipHasher13 { /// /// See: https://131002.net/siphash/ #[unstable(feature = "sip_hash_13", issue = "34767")] -#[rustc_deprecated(since = "1.13.0", reason = "use `DefaultHasher` instead")] +#[rustc_deprecated(since = "1.13.0", + reason = "use `std::collections::hash_map::DefaultHasher` instead")] #[derive(Debug, Clone, Default)] pub struct SipHasher24 { hasher: Hasher, @@ -39,9 +46,6 @@ pub struct SipHasher24 { /// /// See: https://131002.net/siphash/ /// -/// This is currently the default hashing function used by standard library -/// (eg. `collections::HashMap` uses it by default). -/// /// SipHash is a general-purpose hashing function: it runs at a good /// speed (competitive with Spooky and City) and permits strong _keyed_ /// hashing. This lets you key your hashtables from a strong RNG, such as @@ -51,7 +55,8 @@ pub struct SipHasher24 { /// it is not intended for cryptographic purposes. As such, all /// cryptographic uses of this implementation are _strongly discouraged_. #[stable(feature = "rust1", since = "1.0.0")] -#[rustc_deprecated(since = "1.13.0", reason = "use `DefaultHasher` instead")] +#[rustc_deprecated(since = "1.13.0", + reason = "use `std::collections::hash_map::DefaultHasher` instead")] #[derive(Debug, Clone, Default)] pub struct SipHasher(SipHasher24); @@ -78,70 +83,68 @@ struct State { v3: u64, } -// sadly, these macro definitions can't appear later, -// because they're needed in the following defs; -// this design could be improved. - -macro_rules! u8to64_le { - ($buf:expr, $i:expr) => - ($buf[0+$i] as u64 | - ($buf[1+$i] as u64) << 8 | - ($buf[2+$i] as u64) << 16 | - ($buf[3+$i] as u64) << 24 | - ($buf[4+$i] as u64) << 32 | - ($buf[5+$i] as u64) << 40 | - ($buf[6+$i] as u64) << 48 | - ($buf[7+$i] as u64) << 56); - ($buf:expr, $i:expr, $len:expr) => +macro_rules! compress { + ($state:expr) => ({ + compress!($state.v0, $state.v1, $state.v2, $state.v3) + }); + ($v0:expr, $v1:expr, $v2:expr, $v3:expr) => ({ - let mut t = 0; - let mut out = 0; - while t < $len { - out |= ($buf[t+$i] as u64) << t*8; - t += 1; - } - out + $v0 = $v0.wrapping_add($v1); $v1 = $v1.rotate_left(13); $v1 ^= $v0; + $v0 = $v0.rotate_left(32); + $v2 = $v2.wrapping_add($v3); $v3 = $v3.rotate_left(16); $v3 ^= $v2; + $v0 = $v0.wrapping_add($v3); $v3 = $v3.rotate_left(21); $v3 ^= $v0; + $v2 = $v2.wrapping_add($v1); $v1 = $v1.rotate_left(17); $v1 ^= $v2; + $v2 = $v2.rotate_left(32); }); } -/// Load a full u64 word from a byte stream, in LE order. Use +/// Load an integer of the desired type from a byte stream, in LE order. Uses /// `copy_nonoverlapping` to let the compiler generate the most efficient way -/// to load u64 from a possibly unaligned address. +/// to load it from a possibly unaligned address. /// -/// Unsafe because: unchecked indexing at i..i+8 -#[inline] -unsafe fn load_u64_le(buf: &[u8], i: usize) -> u64 { - debug_assert!(i + 8 <= buf.len()); - let mut data = 0u64; - ptr::copy_nonoverlapping(buf.get_unchecked(i), &mut data as *mut _ as *mut u8, 8); - data.to_le() -} - -macro_rules! rotl { - ($x:expr, $b:expr) => - (($x << $b) | ($x >> (64_i32.wrapping_sub($b)))) -} - -macro_rules! compress { - ($state:expr) => ({ - compress!($state.v0, $state.v1, $state.v2, $state.v3) - }); - ($v0:expr, $v1:expr, $v2:expr, $v3:expr) => +/// Unsafe because: unchecked indexing at i..i+size_of(int_ty) +macro_rules! load_int_le { + ($buf:expr, $i:expr, $int_ty:ident) => ({ - $v0 = $v0.wrapping_add($v1); $v1 = rotl!($v1, 13); $v1 ^= $v0; - $v0 = rotl!($v0, 32); - $v2 = $v2.wrapping_add($v3); $v3 = rotl!($v3, 16); $v3 ^= $v2; - $v0 = $v0.wrapping_add($v3); $v3 = rotl!($v3, 21); $v3 ^= $v0; - $v2 = $v2.wrapping_add($v1); $v1 = rotl!($v1, 17); $v1 ^= $v2; - $v2 = rotl!($v2, 32); + debug_assert!($i + mem::size_of::<$int_ty>() <= $buf.len()); + let mut data = 0 as $int_ty; + ptr::copy_nonoverlapping($buf.get_unchecked($i), + &mut data as *mut _ as *mut u8, + mem::size_of::<$int_ty>()); + data.to_le() }); } +/// Load an u64 using up to 7 bytes of a byte slice. +/// +/// Unsafe because: unchecked indexing at start..start+len +#[inline] +unsafe fn u8to64_le(buf: &[u8], start: usize, len: usize) -> u64 { + debug_assert!(len < 8); + let mut i = 0; // current byte index (from LSB) in the output u64 + let mut out = 0; + if i + 3 < len { + out = load_int_le!(buf, start + i, u32) as u64; + i += 4; + } + if i + 1 < len { + out |= (load_int_le!(buf, start + i, u16) as u64) << (i * 8); + i += 2 + } + if i < len { + out |= (*buf.get_unchecked(start + i) as u64) << (i * 8); + i += 1; + } + debug_assert_eq!(i, len); + out +} + impl SipHasher { /// Creates a new `SipHasher` with the two initial keys set to 0. #[inline] #[stable(feature = "rust1", since = "1.0.0")] - #[rustc_deprecated(since = "1.13.0", reason = "use `DefaultHasher` instead")] + #[rustc_deprecated(since = "1.13.0", + reason = "use `std::collections::hash_map::DefaultHasher` instead")] pub fn new() -> SipHasher { SipHasher::new_with_keys(0, 0) } @@ -149,7 +152,8 @@ impl SipHasher { /// Creates a `SipHasher` that is keyed off the provided keys. #[inline] #[stable(feature = "rust1", since = "1.0.0")] - #[rustc_deprecated(since = "1.13.0", reason = "use `DefaultHasher` instead")] + #[rustc_deprecated(since = "1.13.0", + reason = "use `std::collections::hash_map::DefaultHasher` instead")] pub fn new_with_keys(key0: u64, key1: u64) -> SipHasher { SipHasher(SipHasher24::new_with_keys(key0, key1)) } @@ -159,7 +163,8 @@ impl SipHasher13 { /// Creates a new `SipHasher13` with the two initial keys set to 0. #[inline] #[unstable(feature = "sip_hash_13", issue = "34767")] - #[rustc_deprecated(since = "1.13.0", reason = "use `DefaultHasher` instead")] + #[rustc_deprecated(since = "1.13.0", + reason = "use `std::collections::hash_map::DefaultHasher` instead")] pub fn new() -> SipHasher13 { SipHasher13::new_with_keys(0, 0) } @@ -167,7 +172,8 @@ impl SipHasher13 { /// Creates a `SipHasher13` that is keyed off the provided keys. #[inline] #[unstable(feature = "sip_hash_13", issue = "34767")] - #[rustc_deprecated(since = "1.13.0", reason = "use `DefaultHasher` instead")] + #[rustc_deprecated(since = "1.13.0", + reason = "use `std::collections::hash_map::DefaultHasher` instead")] pub fn new_with_keys(key0: u64, key1: u64) -> SipHasher13 { SipHasher13 { hasher: Hasher::new_with_keys(key0, key1) @@ -179,7 +185,8 @@ impl SipHasher24 { /// Creates a new `SipHasher24` with the two initial keys set to 0. #[inline] #[unstable(feature = "sip_hash_13", issue = "34767")] - #[rustc_deprecated(since = "1.13.0", reason = "use `DefaultHasher` instead")] + #[rustc_deprecated(since = "1.13.0", + reason = "use `std::collections::hash_map::DefaultHasher` instead")] pub fn new() -> SipHasher24 { SipHasher24::new_with_keys(0, 0) } @@ -187,7 +194,8 @@ impl SipHasher24 { /// Creates a `SipHasher24` that is keyed off the provided keys. #[inline] #[unstable(feature = "sip_hash_13", issue = "34767")] - #[rustc_deprecated(since = "1.13.0", reason = "use `DefaultHasher` instead")] + #[rustc_deprecated(since = "1.13.0", + reason = "use `std::collections::hash_map::DefaultHasher` instead")] pub fn new_with_keys(key0: u64, key1: u64) -> SipHasher24 { SipHasher24 { hasher: Hasher::new_with_keys(key0, key1) @@ -225,6 +233,37 @@ impl Hasher { self.state.v3 = self.k1 ^ 0x7465646279746573; self.ntail = 0; } + + // Specialized write function that is only valid for buffers with len <= 8. + // It's used to force inlining of write_u8 and write_usize, those would normally be inlined + // except for composite types (that includes slices and str hashing because of delimiter). + // Without this extra push the compiler is very reluctant to inline delimiter writes, + // degrading performance substantially for the most common use cases. + #[inline(always)] + fn short_write(&mut self, msg: &[u8]) { + debug_assert!(msg.len() <= 8); + let length = msg.len(); + self.length += length; + + let needed = 8 - self.ntail; + let fill = cmp::min(length, needed); + if fill == 8 { + self.tail = unsafe { load_int_le!(msg, 0, u64) }; + } else { + self.tail |= unsafe { u8to64_le(msg, 0, fill) } << (8 * self.ntail); + if length < needed { + self.ntail += length; + return; + } + } + self.state.v3 ^= self.tail; + S::c_rounds(&mut self.state); + self.state.v0 ^= self.tail; + + // Buffered tail is now flushed, process new input. + self.ntail = length - needed; + self.tail = unsafe { u8to64_le(msg, needed, self.ntail) }; + } } #[stable(feature = "rust1", since = "1.0.0")] @@ -267,6 +306,21 @@ impl super::Hasher for SipHasher24 { } impl super::Hasher for Hasher { + // see short_write comment for explanation + #[inline] + fn write_usize(&mut self, i: usize) { + let bytes = unsafe { + ::slice::from_raw_parts(&i as *const usize as *const u8, mem::size_of::()) + }; + self.short_write(bytes); + } + + // see short_write comment for explanation + #[inline] + fn write_u8(&mut self, i: u8) { + self.short_write(&[i]); + } + #[inline] fn write(&mut self, msg: &[u8]) { let length = msg.len(); @@ -276,19 +330,16 @@ impl super::Hasher for Hasher { if self.ntail != 0 { needed = 8 - self.ntail; + self.tail |= unsafe { u8to64_le(msg, 0, cmp::min(length, needed)) } << 8 * self.ntail; if length < needed { - self.tail |= u8to64_le!(msg, 0, length) << 8 * self.ntail; self.ntail += length; return + } else { + self.state.v3 ^= self.tail; + S::c_rounds(&mut self.state); + self.state.v0 ^= self.tail; + self.ntail = 0; } - - let m = self.tail | u8to64_le!(msg, 0, needed) << 8 * self.ntail; - - self.state.v3 ^= m; - S::c_rounds(&mut self.state); - self.state.v0 ^= m; - - self.ntail = 0; } // Buffered tail is now flushed, process new input. @@ -297,7 +348,7 @@ impl super::Hasher for Hasher { let mut i = needed; while i < len - left { - let mi = unsafe { load_u64_le(msg, i) }; + let mi = unsafe { load_int_le!(msg, i, u64) }; self.state.v3 ^= mi; S::c_rounds(&mut self.state); @@ -306,7 +357,7 @@ impl super::Hasher for Hasher { i += 8; } - self.tail = u8to64_le!(msg, i, left); + self.tail = unsafe { u8to64_le(msg, i, left) }; self.ntail = left; } diff --git a/src/libcore/internal_macros.rs b/src/libcore/internal_macros.rs new file mode 100644 index 0000000000..f2cdc9d6a9 --- /dev/null +++ b/src/libcore/internal_macros.rs @@ -0,0 +1,62 @@ +// Copyright 2016 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + + +// implements the unary operator "op &T" +// based on "op T" where T is expected to be `Copy`able +macro_rules! forward_ref_unop { + (impl $imp:ident, $method:ident for $t:ty) => { + #[stable(feature = "rust1", since = "1.0.0")] + impl<'a> $imp for &'a $t { + type Output = <$t as $imp>::Output; + + #[inline] + fn $method(self) -> <$t as $imp>::Output { + $imp::$method(*self) + } + } + } +} + +// implements binary operators "&T op U", "T op &U", "&T op &U" +// based on "T op U" where T and U are expected to be `Copy`able +macro_rules! forward_ref_binop { + (impl $imp:ident, $method:ident for $t:ty, $u:ty) => { + #[stable(feature = "rust1", since = "1.0.0")] + impl<'a> $imp<$u> for &'a $t { + type Output = <$t as $imp<$u>>::Output; + + #[inline] + fn $method(self, other: $u) -> <$t as $imp<$u>>::Output { + $imp::$method(*self, other) + } + } + + #[stable(feature = "rust1", since = "1.0.0")] + impl<'a> $imp<&'a $u> for $t { + type Output = <$t as $imp<$u>>::Output; + + #[inline] + fn $method(self, other: &'a $u) -> <$t as $imp<$u>>::Output { + $imp::$method(self, *other) + } + } + + #[stable(feature = "rust1", since = "1.0.0")] + impl<'a, 'b> $imp<&'a $u> for &'b $t { + type Output = <$t as $imp<$u>>::Output; + + #[inline] + fn $method(self, other: &'a $u) -> <$t as $imp<$u>>::Output { + $imp::$method(*self, *other) + } + } + } +} diff --git a/src/libcore/intrinsics.rs b/src/libcore/intrinsics.rs index 22abe7a99b..e844a15848 100644 --- a/src/libcore/intrinsics.rs +++ b/src/libcore/intrinsics.rs @@ -194,14 +194,12 @@ extern "rust-intrinsic" { /// own, or if it does not enable any significant optimizations. pub fn assume(b: bool); - #[cfg(not(stage0))] /// Hints to the compiler that branch condition is likely to be true. /// Returns the value passed to it. /// /// Any use other than with `if` statements will probably not have an effect. pub fn likely(b: bool) -> bool; - #[cfg(not(stage0))] /// Hints to the compiler that branch condition is likely to be false. /// Returns the value passed to it. /// @@ -596,6 +594,19 @@ extern "rust-intrinsic" { /// Invokes memset on the specified pointer, setting `count * size_of::()` /// bytes of memory starting at `dst` to `val`. + /// + /// # Examples + /// + /// ``` + /// use std::ptr; + /// + /// let mut vec = vec![0; 4]; + /// unsafe { + /// let vec_ptr = vec.as_mut_ptr(); + /// ptr::write_bytes(vec_ptr, b'a', 2); + /// } + /// assert_eq!(vec, [b'a', b'a', 0, 0]); + /// ``` #[stable(feature = "rust1", since = "1.0.0")] pub fn write_bytes(dst: *mut T, val: u8, count: usize); diff --git a/src/libcore/iter/iterator.rs b/src/libcore/iter/iterator.rs index 0e74bbe9c2..5a12f5db19 100644 --- a/src/libcore/iter/iterator.rs +++ b/src/libcore/iter/iterator.rs @@ -195,13 +195,9 @@ pub trait Iterator { last } - /// Consumes the `n` first elements of the iterator, then returns the - /// `next()` one. + /// Returns the `n`th element of the iterator. /// - /// This method will evaluate the iterator `n` times, discarding those elements. - /// After it does so, it will call [`next()`] and return its value. - /// - /// [`next()`]: #tymethod.next + /// Note that all preceding elements will be consumed (i.e. discarded). /// /// Like most indexing operations, the count starts from zero, so `nth(0)` /// returns the first value, `nth(1)` the second, and so on. diff --git a/src/libcore/iter/mod.rs b/src/libcore/iter/mod.rs index dd57fd1b51..cd2e0cb11d 100644 --- a/src/libcore/iter/mod.rs +++ b/src/libcore/iter/mod.rs @@ -328,6 +328,8 @@ pub use self::traits::{FromIterator, IntoIterator, DoubleEndedIterator, Extend}; pub use self::traits::{ExactSizeIterator, Sum, Product}; #[unstable(feature = "fused", issue = "35602")] pub use self::traits::FusedIterator; +#[unstable(feature = "trusted_len", issue = "37572")] +pub use self::traits::TrustedLen; mod iterator; mod range; @@ -372,6 +374,10 @@ impl ExactSizeIterator for Rev impl FusedIterator for Rev where I: FusedIterator + DoubleEndedIterator {} +#[unstable(feature = "trusted_len", issue = "37572")] +unsafe impl TrustedLen for Rev + where I: TrustedLen + DoubleEndedIterator {} + /// An iterator that clones the elements of an underlying iterator. /// /// This `struct` is created by the [`cloned()`] method on [`Iterator`]. See its @@ -386,7 +392,7 @@ pub struct Cloned { it: I, } -#[stable(feature = "rust1", since = "1.0.0")] +#[stable(feature = "iter_cloned", since = "1.1.0")] impl<'a, I, T: 'a> Iterator for Cloned where I: Iterator, T: Clone { @@ -399,9 +405,15 @@ impl<'a, I, T: 'a> Iterator for Cloned fn size_hint(&self) -> (usize, Option) { self.it.size_hint() } + + fn fold(self, init: Acc, mut f: F) -> Acc + where F: FnMut(Acc, Self::Item) -> Acc, + { + self.it.fold(init, move |acc, elt| f(acc, elt.clone())) + } } -#[stable(feature = "rust1", since = "1.0.0")] +#[stable(feature = "iter_cloned", since = "1.1.0")] impl<'a, I, T: 'a> DoubleEndedIterator for Cloned where I: DoubleEndedIterator, T: Clone { @@ -410,7 +422,7 @@ impl<'a, I, T: 'a> DoubleEndedIterator for Cloned } } -#[stable(feature = "rust1", since = "1.0.0")] +#[stable(feature = "iter_cloned", since = "1.1.0")] impl<'a, I, T: 'a> ExactSizeIterator for Cloned where I: ExactSizeIterator, T: Clone {} @@ -420,6 +432,24 @@ impl<'a, I, T: 'a> FusedIterator for Cloned where I: FusedIterator, T: Clone {} +#[doc(hidden)] +unsafe impl<'a, I, T: 'a> TrustedRandomAccess for Cloned + where I: TrustedRandomAccess, T: Clone +{ + unsafe fn get_unchecked(&mut self, i: usize) -> Self::Item { + self.it.get_unchecked(i).clone() + } + + #[inline] + fn may_have_side_effect() -> bool { true } +} + +#[unstable(feature = "trusted_len", issue = "37572")] +unsafe impl<'a, I, T: 'a> TrustedLen for Cloned + where I: TrustedLen, + T: Clone +{} + /// An iterator that repeats endlessly. /// /// This `struct` is created by the [`cycle()`] method on [`Iterator`]. See its @@ -532,6 +562,25 @@ impl Iterator for Chain where } } + fn fold(self, init: Acc, mut f: F) -> Acc + where F: FnMut(Acc, Self::Item) -> Acc, + { + let mut accum = init; + match self.state { + ChainState::Both | ChainState::Front => { + accum = self.a.fold(accum, &mut f); + } + _ => { } + } + match self.state { + ChainState::Both | ChainState::Back => { + accum = self.b.fold(accum, &mut f); + } + _ => { } + } + accum + } + #[inline] fn nth(&mut self, mut n: usize) -> Option { match self.state { @@ -630,6 +679,11 @@ impl FusedIterator for Chain B: FusedIterator, {} +#[unstable(feature = "trusted_len", issue = "37572")] +unsafe impl TrustedLen for Chain + where A: TrustedLen, B: TrustedLen, +{} + /// An iterator that iterates two other iterators simultaneously. /// /// This `struct` is created by the [`zip()`] method on [`Iterator`]. See its @@ -773,6 +827,13 @@ impl ZipImpl for Zip unsafe { Some((self.a.get_unchecked(i), self.b.get_unchecked(i))) } + } else if A::may_have_side_effect() && self.index < self.a.len() { + // match the base implementation's potential side effects + unsafe { + self.a.get_unchecked(self.index); + } + self.index += 1; + None } else { None } @@ -789,6 +850,23 @@ impl ZipImpl for Zip where A: DoubleEndedIterator + ExactSizeIterator, B: DoubleEndedIterator + ExactSizeIterator { + // Adjust a, b to equal length + if A::may_have_side_effect() { + let sz = self.a.len(); + if sz > self.len { + for _ in 0..sz - cmp::max(self.len, self.index) { + self.a.next_back(); + } + } + } + if B::may_have_side_effect() { + let sz = self.b.len(); + if sz > self.len { + for _ in 0..sz - self.len { + self.b.next_back(); + } + } + } if self.index < self.len { self.len -= 1; let i = self.len; @@ -814,12 +892,20 @@ unsafe impl TrustedRandomAccess for Zip (self.a.get_unchecked(i), self.b.get_unchecked(i)) } + fn may_have_side_effect() -> bool { + A::may_have_side_effect() || B::may_have_side_effect() + } } #[unstable(feature = "fused", issue = "35602")] impl FusedIterator for Zip where A: FusedIterator, B: FusedIterator, {} +#[unstable(feature = "trusted_len", issue = "37572")] +unsafe impl TrustedLen for Zip + where A: TrustedLen, B: TrustedLen, +{} + /// An iterator that maps the values of `iter` with `f`. /// /// This `struct` is created by the [`map()`] method on [`Iterator`]. See its @@ -900,6 +986,13 @@ impl Iterator for Map where F: FnMut(I::Item) -> B { fn size_hint(&self) -> (usize, Option) { self.iter.size_hint() } + + fn fold(self, init: Acc, mut g: G) -> Acc + where G: FnMut(Acc, Self::Item) -> Acc, + { + let mut f = self.f; + self.iter.fold(init, move |acc, elt| g(acc, f(elt))) + } } #[stable(feature = "rust1", since = "1.0.0")] @@ -920,6 +1013,23 @@ impl ExactSizeIterator for Map impl FusedIterator for Map where F: FnMut(I::Item) -> B {} +#[unstable(feature = "trusted_len", issue = "37572")] +unsafe impl TrustedLen for Map + where I: TrustedLen, + F: FnMut(I::Item) -> B {} + +#[doc(hidden)] +unsafe impl TrustedRandomAccess for Map + where I: TrustedRandomAccess, + F: FnMut(I::Item) -> B, +{ + unsafe fn get_unchecked(&mut self, i: usize) -> Self::Item { + (self.f)(self.iter.get_unchecked(i)) + } + #[inline] + fn may_have_side_effect() -> bool { true } +} + /// An iterator that filters the elements of `iter` with `predicate`. /// /// This `struct` is created by the [`filter()`] method on [`Iterator`]. See its @@ -1135,11 +1245,21 @@ unsafe impl TrustedRandomAccess for Enumerate unsafe fn get_unchecked(&mut self, i: usize) -> (usize, I::Item) { (self.count + i, self.iter.get_unchecked(i)) } + + fn may_have_side_effect() -> bool { + I::may_have_side_effect() + } } #[unstable(feature = "fused", issue = "35602")] impl FusedIterator for Enumerate where I: FusedIterator {} +#[unstable(feature = "trusted_len", issue = "37572")] +unsafe impl TrustedLen for Enumerate + where I: TrustedLen, +{} + + /// An iterator with a `peek()` that returns an optional reference to the next /// element. /// @@ -1254,10 +1374,7 @@ impl Peekable { if self.peeked.is_none() { self.peeked = self.iter.next(); } - match self.peeked { - Some(ref value) => Some(value), - None => None, - } + self.peeked.as_ref() } } @@ -1764,6 +1881,10 @@ unsafe impl TrustedRandomAccess for Fuse unsafe fn get_unchecked(&mut self, i: usize) -> I::Item { self.iter.get_unchecked(i) } + + fn may_have_side_effect() -> bool { + I::may_have_side_effect() + } } #[unstable(feature = "fused", issue = "35602")] diff --git a/src/libcore/iter/range.rs b/src/libcore/iter/range.rs index 66d05d81d8..e6f21d6c17 100644 --- a/src/libcore/iter/range.rs +++ b/src/libcore/iter/range.rs @@ -12,7 +12,7 @@ use mem; use ops::{self, Add, Sub}; use usize; -use super::FusedIterator; +use super::{FusedIterator, TrustedLen}; /// Objects that can be stepped over in both directions. /// @@ -96,12 +96,12 @@ macro_rules! step_impl_unsigned { #[inline] fn add_one(&self) -> Self { - *self + 1 + Add::add(*self, 1) } #[inline] fn sub_one(&self) -> Self { - *self - 1 + Sub::sub(*self, 1) } #[inline] @@ -167,12 +167,12 @@ macro_rules! step_impl_signed { #[inline] fn add_one(&self) -> Self { - *self + 1 + Add::add(*self, 1) } #[inline] fn sub_one(&self) -> Self { - *self - 1 + Sub::sub(*self, 1) } #[inline] @@ -216,12 +216,12 @@ macro_rules! step_impl_no_between { #[inline] fn add_one(&self) -> Self { - *self + 1 + Add::add(*self, 1) } #[inline] fn sub_one(&self) -> Self { - *self - 1 + Sub::sub(*self, 1) } #[inline] @@ -328,7 +328,8 @@ impl ops::RangeInclusive { } } -#[stable(feature = "rust1", since = "1.0.0")] +#[unstable(feature = "step_by", reason = "recent addition", + issue = "27741")] impl Iterator for StepBy> where A: Clone, for<'a> &'a A: Add<&'a A, Output = A> @@ -352,7 +353,8 @@ impl Iterator for StepBy> where impl FusedIterator for StepBy> where A: Clone, for<'a> &'a A: Add<&'a A, Output = A> {} -#[stable(feature = "rust1", since = "1.0.0")] +#[unstable(feature = "step_by", reason = "recent addition", + issue = "27741")] impl Iterator for StepBy> { type Item = A; @@ -466,7 +468,11 @@ macro_rules! range_exact_iter_impl { ($($t:ty)*) => ($( #[stable(feature = "rust1", since = "1.0.0")] impl ExactSizeIterator for ops::Range<$t> { } + )*) +} +macro_rules! range_incl_exact_iter_impl { + ($($t:ty)*) => ($( #[unstable(feature = "inclusive_range", reason = "recently added, follows RFC", issue = "28237")] @@ -474,6 +480,22 @@ macro_rules! range_exact_iter_impl { )*) } +macro_rules! range_trusted_len_impl { + ($($t:ty)*) => ($( + #[unstable(feature = "trusted_len", issue = "37572")] + unsafe impl TrustedLen for ops::Range<$t> { } + )*) +} + +macro_rules! range_incl_trusted_len_impl { + ($($t:ty)*) => ($( + #[unstable(feature = "inclusive_range", + reason = "recently added, follows RFC", + issue = "28237")] + unsafe impl TrustedLen for ops::RangeInclusive<$t> { } + )*) +} + #[stable(feature = "rust1", since = "1.0.0")] impl Iterator for ops::Range where for<'a> &'a A: Add<&'a A, Output = A> @@ -500,9 +522,19 @@ impl Iterator for ops::Range where } } -// Ranges of u64 and i64 are excluded because they cannot guarantee having -// a length <= usize::MAX, which is required by ExactSizeIterator. +// These macros generate `ExactSizeIterator` impls for various range types. +// Range<{u,i}64> and RangeInclusive<{u,i}{32,64,size}> are excluded +// because they cannot guarantee having a length <= usize::MAX, which is +// required by ExactSizeIterator. range_exact_iter_impl!(usize u8 u16 u32 isize i8 i16 i32); +range_incl_exact_iter_impl!(u8 u16 i8 i16); + +// These macros generate `TrustedLen` impls. +// +// They need to guarantee that .size_hint() is either exact, or that +// the upper bound is None when it does not fit the type limits. +range_trusted_len_impl!(usize isize u8 i8 u16 i16 u32 i32 i64 u64); +range_incl_trusted_len_impl!(usize isize u8 i8 u16 i16 u32 i32 i64 u64); #[stable(feature = "rust1", since = "1.0.0")] impl DoubleEndedIterator for ops::Range where diff --git a/src/libcore/iter/traits.rs b/src/libcore/iter/traits.rs index b55d6f96af..bc4be073c5 100644 --- a/src/libcore/iter/traits.rs +++ b/src/libcore/iter/traits.rs @@ -8,6 +8,7 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. use ops::{Mul, Add}; +use num::Wrapping; /// Conversion from an `Iterator`. /// @@ -584,35 +585,39 @@ pub trait Product: Sized { // NB: explicitly use Add and Mul here to inherit overflow checks macro_rules! integer_sum_product { - ($($a:ident)*) => ($( + (@impls $zero:expr, $one:expr, $($a:ty)*) => ($( #[stable(feature = "iter_arith_traits", since = "1.12.0")] impl Sum for $a { fn sum>(iter: I) -> $a { - iter.fold(0, Add::add) + iter.fold($zero, Add::add) } } #[stable(feature = "iter_arith_traits", since = "1.12.0")] impl Product for $a { fn product>(iter: I) -> $a { - iter.fold(1, Mul::mul) + iter.fold($one, Mul::mul) } } #[stable(feature = "iter_arith_traits", since = "1.12.0")] impl<'a> Sum<&'a $a> for $a { fn sum>(iter: I) -> $a { - iter.cloned().fold(0, Add::add) + iter.fold($zero, Add::add) } } #[stable(feature = "iter_arith_traits", since = "1.12.0")] impl<'a> Product<&'a $a> for $a { fn product>(iter: I) -> $a { - iter.cloned().fold(1, Mul::mul) + iter.fold($one, Mul::mul) } } - )*) + )*); + ($($a:ty)*) => ( + integer_sum_product!(@impls 0, 1, $($a)+); + integer_sum_product!(@impls Wrapping(0), Wrapping(1), $(Wrapping<$a>)+); + ); } macro_rules! float_sum_product { @@ -665,3 +670,22 @@ pub trait FusedIterator: Iterator {} #[unstable(feature = "fused", issue = "35602")] impl<'a, I: FusedIterator + ?Sized> FusedIterator for &'a mut I {} + +/// An iterator that reports an accurate length using size_hint. +/// +/// The iterator reports a size hint where it is either exact +/// (lower bound is equal to upper bound), or the upper bound is `None`. +/// The upper bound must only be `None` if the actual iterator length is +/// larger than `usize::MAX`. +/// +/// The iterator must produce exactly the number of elements it reported. +/// +/// # Safety +/// +/// This trait must only be implemented when the contract is upheld. +/// Consumers of this trait must inspect `.size_hint()`’s upper bound. +#[unstable(feature = "trusted_len", issue = "37572")] +pub unsafe trait TrustedLen : Iterator {} + +#[unstable(feature = "trusted_len", issue = "37572")] +unsafe impl<'a, I: TrustedLen + ?Sized> TrustedLen for &'a mut I {} diff --git a/src/libcore/iter_private.rs b/src/libcore/iter_private.rs index 83eeef31ab..bc1aaa09f3 100644 --- a/src/libcore/iter_private.rs +++ b/src/libcore/iter_private.rs @@ -14,6 +14,7 @@ /// # Safety /// /// The iterator's .len() and size_hint() must be exact. +/// `.len()` must be cheap to call. /// /// .get_unchecked() must return distinct mutable references for distinct /// indices (if applicable), and must return a valid reference if index is in @@ -21,5 +22,7 @@ #[doc(hidden)] pub unsafe trait TrustedRandomAccess : ExactSizeIterator { unsafe fn get_unchecked(&mut self, i: usize) -> Self::Item; + /// Return `true` if getting an iterator element may have + /// side effects. Remember to take inner iterators into account. + fn may_have_side_effect() -> bool; } - diff --git a/src/libcore/lib.rs b/src/libcore/lib.rs index 28101d21fc..07f5e725e2 100644 --- a/src/libcore/lib.rs +++ b/src/libcore/lib.rs @@ -100,6 +100,9 @@ use prelude::v1::*; #[macro_use] mod macros; +#[macro_use] +mod internal_macros; + #[path = "num/float_macros.rs"] #[macro_use] mod float_macros; diff --git a/src/libcore/macros.rs b/src/libcore/macros.rs index 6e08abd346..23c2e2142c 100644 --- a/src/libcore/macros.rs +++ b/src/libcore/macros.rs @@ -42,12 +42,13 @@ macro_rules! panic { /// Unsafe code relies on `assert!` to enforce run-time invariants that, if /// violated could lead to unsafety. /// -/// Other use-cases of `assert!` include -/// [testing](https://doc.rust-lang.org/book/testing.html) and enforcing -/// run-time invariants in safe code (whose violation cannot result in unsafety). +/// Other use-cases of `assert!` include [testing] and enforcing run-time +/// invariants in safe code (whose violation cannot result in unsafety). /// /// This macro has a second version, where a custom panic message can be provided. /// +/// [testing]: ../book/testing.html +/// /// # Examples /// /// ``` @@ -316,26 +317,27 @@ macro_rules! try { /// Write formatted data into a buffer /// -/// This macro accepts any value with `write_fmt` method as a writer, a format string, and a list -/// of arguments to format. +/// This macro accepts a 'writer' (any value with a `write_fmt` method), a format string, and a +/// list of arguments to format. /// -/// `write_fmt` method usually comes from an implementation of [`std::fmt::Write`][fmt_write] or -/// [`std::io::Write`][io_write] traits. These are sometimes called 'writers'. +/// The `write_fmt` method usually comes from an implementation of [`std::fmt::Write`][fmt_write] +/// or [`std::io::Write`][io_write] traits. The term 'writer' refers to an implementation of one of +/// these two traits. /// /// Passed arguments will be formatted according to the specified format string and the resulting /// string will be passed to the writer. /// /// See [`std::fmt`][fmt] for more information on format syntax. /// -/// Return value is completely dependent on the 'write_fmt' method. +/// `write!` returns whatever the 'write_fmt' method returns. /// -/// Common return values are: [`Result`][enum_result], [`io::Result`][type_result] +/// Common return values include: [`fmt::Result`][fmt_result], [`io::Result`][io_result] /// /// [fmt]: ../std/fmt/index.html /// [fmt_write]: ../std/fmt/trait.Write.html /// [io_write]: ../std/io/trait.Write.html -/// [enum_result]: ../std/result/enum.Result.html -/// [type_result]: ../std/io/type.Result.html +/// [fmt_result]: ../std/fmt/type.Result.html +/// [io_result]: ../std/io/type.Result.html /// /// # Examples /// @@ -354,31 +356,32 @@ macro_rules! write { ($dst:expr, $($arg:tt)*) => ($dst.write_fmt(format_args!($($arg)*))) } -/// Write formatted data into a buffer, with appending a newline. +/// Write formatted data into a buffer, with a newline appended. /// /// On all platforms, the newline is the LINE FEED character (`\n`/`U+000A`) alone /// (no additional CARRIAGE RETURN (`\r`/`U+000D`). /// -/// This macro accepts any value with `write_fmt` method as a writer, a format string, and a list -/// of arguments to format. +/// This macro accepts a 'writer' (any value with a `write_fmt` method), a format string, and a +/// list of arguments to format. /// -/// `write_fmt` method usually comes from an implementation of [`std::fmt::Write`][fmt_write] or -/// [`std::io::Write`][io_write] traits. These are sometimes called 'writers'. +/// The `write_fmt` method usually comes from an implementation of [`std::fmt::Write`][fmt_write] +/// or [`std::io::Write`][io_write] traits. The term 'writer' refers to an implementation of one of +/// these two traits. /// /// Passed arguments will be formatted according to the specified format string and the resulting -/// string will be passed to the writer. +/// string will be passed to the writer, along with the appended newline. /// /// See [`std::fmt`][fmt] for more information on format syntax. /// -/// Return value is completely dependent on the 'write_fmt' method. +/// `write!` returns whatever the 'write_fmt' method returns. /// -/// Common return values are: [`Result`][enum_result], [`io::Result`][type_result] +/// Common return values include: [`fmt::Result`][fmt_result], [`io::Result`][io_result] /// /// [fmt]: ../std/fmt/index.html /// [fmt_write]: ../std/fmt/trait.Write.html /// [io_write]: ../std/io/trait.Write.html -/// [enum_result]: ../std/result/enum.Result.html -/// [type_result]: ../std/io/type.Result.html +/// [fmt_result]: ../std/fmt/type.Result.html +/// [io_result]: ../std/io/type.Result.html /// /// # Examples /// @@ -509,3 +512,156 @@ macro_rules! unreachable { macro_rules! unimplemented { () => (panic!("not yet implemented")) } + +/// Built-in macros to the compiler itself. +/// +/// These macros do not have any corresponding definition with a `macro_rules!` +/// macro, but are documented here. Their implementations can be found hardcoded +/// into libsyntax itself. +/// +/// For more information, see documentation for `std`'s macros. +mod builtin { + /// The core macro for formatted string creation & output. + /// + /// For more information, see the documentation for [`std::format_args!`]. + /// + /// [`std::format_args!`]: ../std/macro.format_args.html + #[stable(feature = "rust1", since = "1.0.0")] + #[macro_export] + #[cfg(dox)] + macro_rules! format_args { ($fmt:expr, $($args:tt)*) => ({ + /* compiler built-in */ + }) } + + /// Inspect an environment variable at compile time. + /// + /// For more information, see the documentation for [`std::env!`]. + /// + /// [`std::env!`]: ../std/macro.env.html + #[stable(feature = "rust1", since = "1.0.0")] + #[macro_export] + #[cfg(dox)] + macro_rules! env { ($name:expr) => ({ /* compiler built-in */ }) } + + /// Optionally inspect an environment variable at compile time. + /// + /// For more information, see the documentation for [`std::option_env!`]. + /// + /// [`std::option_env!`]: ../std/macro.option_env.html + #[stable(feature = "rust1", since = "1.0.0")] + #[macro_export] + #[cfg(dox)] + macro_rules! option_env { ($name:expr) => ({ /* compiler built-in */ }) } + + /// Concatenate identifiers into one identifier. + /// + /// For more information, see the documentation for [`std::concat_idents!`]. + /// + /// [`std::concat_idents!`]: ../std/macro.concat_idents.html + #[unstable(feature = "concat_idents_macro", issue = "29599")] + #[macro_export] + #[cfg(dox)] + macro_rules! concat_idents { + ($($e:ident),*) => ({ /* compiler built-in */ }) + } + + /// Concatenates literals into a static string slice. + /// + /// For more information, see the documentation for [`std::concat!`]. + /// + /// [`std::concat!`]: ../std/macro.concat.html + #[stable(feature = "rust1", since = "1.0.0")] + #[macro_export] + #[cfg(dox)] + macro_rules! concat { ($($e:expr),*) => ({ /* compiler built-in */ }) } + + /// A macro which expands to the line number on which it was invoked. + /// + /// For more information, see the documentation for [`std::line!`]. + /// + /// [`std::line!`]: ../std/macro.line.html + #[stable(feature = "rust1", since = "1.0.0")] + #[macro_export] + #[cfg(dox)] + macro_rules! line { () => ({ /* compiler built-in */ }) } + + /// A macro which expands to the column number on which it was invoked. + /// + /// For more information, see the documentation for [`std::column!`]. + /// + /// [`std::column!`]: ../std/macro.column.html + #[stable(feature = "rust1", since = "1.0.0")] + #[macro_export] + #[cfg(dox)] + macro_rules! column { () => ({ /* compiler built-in */ }) } + + /// A macro which expands to the file name from which it was invoked. + /// + /// For more information, see the documentation for [`std::file!`]. + /// + /// [`std::file!`]: ../std/macro.file.html + #[stable(feature = "rust1", since = "1.0.0")] + #[macro_export] + #[cfg(dox)] + macro_rules! file { () => ({ /* compiler built-in */ }) } + + /// A macro which stringifies its argument. + /// + /// For more information, see the documentation for [`std::stringify!`]. + /// + /// [`std::stringify!`]: ../std/macro.stringify.html + #[stable(feature = "rust1", since = "1.0.0")] + #[macro_export] + #[cfg(dox)] + macro_rules! stringify { ($t:tt) => ({ /* compiler built-in */ }) } + + /// Includes a utf8-encoded file as a string. + /// + /// For more information, see the documentation for [`std::include_str!`]. + /// + /// [`std::include_str!`]: ../std/macro.include_str.html + #[stable(feature = "rust1", since = "1.0.0")] + #[macro_export] + #[cfg(dox)] + macro_rules! include_str { ($file:expr) => ({ /* compiler built-in */ }) } + + /// Includes a file as a reference to a byte array. + /// + /// For more information, see the documentation for [`std::include_bytes!`]. + /// + /// [`std::include_bytes!`]: ../std/macro.include_bytes.html + #[stable(feature = "rust1", since = "1.0.0")] + #[macro_export] + #[cfg(dox)] + macro_rules! include_bytes { ($file:expr) => ({ /* compiler built-in */ }) } + + /// Expands to a string that represents the current module path. + /// + /// For more information, see the documentation for [`std::module_path!`]. + /// + /// [`std::module_path!`]: ../std/macro.module_path.html + #[stable(feature = "rust1", since = "1.0.0")] + #[macro_export] + #[cfg(dox)] + macro_rules! module_path { () => ({ /* compiler built-in */ }) } + + /// Boolean evaluation of configuration flags. + /// + /// For more information, see the documentation for [`std::cfg!`]. + /// + /// [`std::cfg!`]: ../std/macro.cfg.html + #[stable(feature = "rust1", since = "1.0.0")] + #[macro_export] + #[cfg(dox)] + macro_rules! cfg { ($($cfg:tt)*) => ({ /* compiler built-in */ }) } + + /// Parse a file as an expression or an item according to the context. + /// + /// For more information, see the documentation for [`std::include!`]. + /// + /// [`std::include!`]: ../std/macro.include.html + #[stable(feature = "rust1", since = "1.0.0")] + #[macro_export] + #[cfg(dox)] + macro_rules! include { ($file:expr) => ({ /* compiler built-in */ }) } +} diff --git a/src/libcore/marker.rs b/src/libcore/marker.rs index 03d8af1563..bdb0dd8e7d 100644 --- a/src/libcore/marker.rs +++ b/src/libcore/marker.rs @@ -241,8 +241,8 @@ pub trait Unsize { /// compile-time error. Specifically, with structs you'll get [E0204] and with enums you'll get /// [E0205]. /// -/// [E0204]: https://doc.rust-lang.org/error-index.html#E0204 -/// [E0205]: https://doc.rust-lang.org/error-index.html#E0205 +/// [E0204]: ../../error-index.html#E0204 +/// [E0205]: ../../error-index.html#E0205 /// /// ## When *should* my type be `Copy`? /// diff --git a/src/libcore/mem.rs b/src/libcore/mem.rs index d3b8a60b79..e0aa25724c 100644 --- a/src/libcore/mem.rs +++ b/src/libcore/mem.rs @@ -15,7 +15,12 @@ #![stable(feature = "rust1", since = "1.0.0")] +use clone; +use cmp; +use fmt; +use hash; use intrinsics; +use marker::{Copy, PhantomData, Sized}; use ptr; #[stable(feature = "rust1", since = "1.0.0")] @@ -647,3 +652,80 @@ pub fn drop(_x: T) { } pub unsafe fn transmute_copy(src: &T) -> U { ptr::read(src as *const T as *const U) } + +/// Opaque type representing the discriminant of an enum. +/// +/// See the `discriminant` function in this module for more information. +#[unstable(feature = "discriminant_value", reason = "recently added, follows RFC", issue = "24263")] +pub struct Discriminant(u64, PhantomData<*const T>); + +// N.B. These trait implementations cannot be derived because we don't want any bounds on T. + +#[unstable(feature = "discriminant_value", reason = "recently added, follows RFC", issue = "24263")] +impl Copy for Discriminant {} + +#[unstable(feature = "discriminant_value", reason = "recently added, follows RFC", issue = "24263")] +impl clone::Clone for Discriminant { + fn clone(&self) -> Self { + *self + } +} + +#[unstable(feature = "discriminant_value", reason = "recently added, follows RFC", issue = "24263")] +impl cmp::PartialEq for Discriminant { + fn eq(&self, rhs: &Self) -> bool { + self.0 == rhs.0 + } +} + +#[unstable(feature = "discriminant_value", reason = "recently added, follows RFC", issue = "24263")] +impl cmp::Eq for Discriminant {} + +#[unstable(feature = "discriminant_value", reason = "recently added, follows RFC", issue = "24263")] +impl hash::Hash for Discriminant { + fn hash(&self, state: &mut H) { + self.0.hash(state); + } +} + +#[unstable(feature = "discriminant_value", reason = "recently added, follows RFC", issue = "24263")] +impl fmt::Debug for Discriminant { + fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result { + fmt.debug_tuple("Discriminant") + .field(&self.0) + .finish() + } +} + +/// Returns a value uniquely identifying the enum variant in `v`. +/// +/// If `T` is not an enum, calling this function will not result in undefined behavior, but the +/// return value is unspecified. +/// +/// # Stability +/// +/// The discriminant of an enum variant may change if the enum definition changes. A discriminant +/// of some variant will not change between compilations with the same compiler. +/// +/// # Examples +/// +/// This can be used to compare enums that carry data, while disregarding +/// the actual data: +/// +/// ``` +/// #![feature(discriminant_value)] +/// use std::mem; +/// +/// enum Foo { A(&'static str), B(i32), C(i32) } +/// +/// assert!(mem::discriminant(&Foo::A("bar")) == mem::discriminant(&Foo::A("baz"))); +/// assert!(mem::discriminant(&Foo::B(1)) == mem::discriminant(&Foo::B(2))); +/// assert!(mem::discriminant(&Foo::B(3)) != mem::discriminant(&Foo::C(3))); +/// ``` +#[unstable(feature = "discriminant_value", reason = "recently added, follows RFC", issue = "24263")] +pub fn discriminant(v: &T) -> Discriminant { + unsafe { + Discriminant(intrinsics::discriminant_value(v), PhantomData) + } +} + diff --git a/src/libcore/num/bignum.rs b/src/libcore/num/bignum.rs index 1ca550c674..a1f4630c30 100644 --- a/src/libcore/num/bignum.rs +++ b/src/libcore/num/bignum.rs @@ -34,19 +34,22 @@ use intrinsics; pub trait FullOps: Sized { /// Returns `(carry', v')` such that `carry' * 2^W + v' = self + other + carry`, /// where `W` is the number of bits in `Self`. - fn full_add(self, other: Self, carry: bool) -> (bool /*carry*/, Self); + fn full_add(self, other: Self, carry: bool) -> (bool /* carry */, Self); /// Returns `(carry', v')` such that `carry' * 2^W + v' = self * other + carry`, /// where `W` is the number of bits in `Self`. - fn full_mul(self, other: Self, carry: Self) -> (Self /*carry*/, Self); + fn full_mul(self, other: Self, carry: Self) -> (Self /* carry */, Self); /// Returns `(carry', v')` such that `carry' * 2^W + v' = self * other + other2 + carry`, /// where `W` is the number of bits in `Self`. - fn full_mul_add(self, other: Self, other2: Self, carry: Self) -> (Self /*carry*/, Self); + fn full_mul_add(self, other: Self, other2: Self, carry: Self) -> (Self /* carry */, Self); /// Returns `(quo, rem)` such that `borrow * 2^W + self = quo * other + rem` /// and `0 <= rem < other`, where `W` is the number of bits in `Self`. - fn full_div_rem(self, other: Self, borrow: Self) -> (Self /*quotient*/, Self /*remainder*/); + fn full_div_rem(self, + other: Self, + borrow: Self) + -> (Self /* quotient */, Self /* remainder */); } macro_rules! impl_full_ops { @@ -100,11 +103,7 @@ impl_full_ops! { /// Table of powers of 5 representable in digits. Specifically, the largest {u8, u16, u32} value /// that's a power of five, plus the corresponding exponent. Used in `mul_pow5`. -const SMALL_POW5: [(u64, usize); 3] = [ - (125, 3), - (15625, 6), - (1_220_703_125, 13), -]; +const SMALL_POW5: [(u64, usize); 3] = [(125, 3), (15625, 6), (1_220_703_125, 13)]; macro_rules! define_bignum { ($name:ident: type=$ty:ty, n=$n:expr) => ( diff --git a/src/libcore/num/diy_float.rs b/src/libcore/num/diy_float.rs index 7c369ee3b3..11eea753f9 100644 --- a/src/libcore/num/diy_float.rs +++ b/src/libcore/num/diy_float.rs @@ -49,12 +49,30 @@ impl Fp { pub fn normalize(&self) -> Fp { let mut f = self.f; let mut e = self.e; - if f >> (64 - 32) == 0 { f <<= 32; e -= 32; } - if f >> (64 - 16) == 0 { f <<= 16; e -= 16; } - if f >> (64 - 8) == 0 { f <<= 8; e -= 8; } - if f >> (64 - 4) == 0 { f <<= 4; e -= 4; } - if f >> (64 - 2) == 0 { f <<= 2; e -= 2; } - if f >> (64 - 1) == 0 { f <<= 1; e -= 1; } + if f >> (64 - 32) == 0 { + f <<= 32; + e -= 32; + } + if f >> (64 - 16) == 0 { + f <<= 16; + e -= 16; + } + if f >> (64 - 8) == 0 { + f <<= 8; + e -= 8; + } + if f >> (64 - 4) == 0 { + f <<= 4; + e -= 4; + } + if f >> (64 - 2) == 0 { + f <<= 2; + e -= 2; + } + if f >> (64 - 1) == 0 { + f <<= 1; + e -= 1; + } debug_assert!(f >= (1 >> 63)); Fp { f: f, e: e } } @@ -66,6 +84,9 @@ impl Fp { assert!(edelta >= 0); let edelta = edelta as usize; assert_eq!(self.f << edelta >> edelta, self.f); - Fp { f: self.f << edelta, e: e } + Fp { + f: self.f << edelta, + e: e, + } } } diff --git a/src/libcore/num/f32.rs b/src/libcore/num/f32.rs index 07b05f91f4..4527d46a27 100644 --- a/src/libcore/num/f32.rs +++ b/src/libcore/num/f32.rs @@ -61,13 +61,13 @@ pub const MAX_10_EXP: i32 = 38; /// Not a Number (NaN). #[stable(feature = "rust1", since = "1.0.0")] -pub const NAN: f32 = 0.0_f32/0.0_f32; +pub const NAN: f32 = 0.0_f32 / 0.0_f32; /// Infinity (∞). #[stable(feature = "rust1", since = "1.0.0")] -pub const INFINITY: f32 = 1.0_f32/0.0_f32; +pub const INFINITY: f32 = 1.0_f32 / 0.0_f32; /// Negative infinity (-∞). #[stable(feature = "rust1", since = "1.0.0")] -pub const NEG_INFINITY: f32 = -1.0_f32/0.0_f32; +pub const NEG_INFINITY: f32 = -1.0_f32 / 0.0_f32; /// Basic mathematical constants. #[stable(feature = "rust1", since = "1.0.0")] @@ -144,26 +144,40 @@ pub mod consts { issue = "32110")] impl Float for f32 { #[inline] - fn nan() -> f32 { NAN } + fn nan() -> f32 { + NAN + } #[inline] - fn infinity() -> f32 { INFINITY } + fn infinity() -> f32 { + INFINITY + } #[inline] - fn neg_infinity() -> f32 { NEG_INFINITY } + fn neg_infinity() -> f32 { + NEG_INFINITY + } #[inline] - fn zero() -> f32 { 0.0 } + fn zero() -> f32 { + 0.0 + } #[inline] - fn neg_zero() -> f32 { -0.0 } + fn neg_zero() -> f32 { + -0.0 + } #[inline] - fn one() -> f32 { 1.0 } + fn one() -> f32 { + 1.0 + } /// Returns `true` if the number is NaN. #[inline] - fn is_nan(self) -> bool { self != self } + fn is_nan(self) -> bool { + self != self + } /// Returns `true` if the number is infinite. #[inline] @@ -192,11 +206,11 @@ impl Float for f32 { let bits: u32 = unsafe { mem::transmute(self) }; match (bits & MAN_MASK, bits & EXP_MASK) { - (0, 0) => Fp::Zero, - (_, 0) => Fp::Subnormal, + (0, 0) => Fp::Zero, + (_, 0) => Fp::Subnormal, (0, EXP_MASK) => Fp::Infinite, (_, EXP_MASK) => Fp::Nan, - _ => Fp::Normal, + _ => Fp::Normal, } } @@ -252,7 +266,9 @@ impl Float for f32 { /// Returns the reciprocal (multiplicative inverse) of the number. #[inline] - fn recip(self) -> f32 { 1.0 / self } + fn recip(self) -> f32 { + 1.0 / self + } #[inline] fn powi(self, n: i32) -> f32 { @@ -261,7 +277,9 @@ impl Float for f32 { /// Converts to degrees, assuming the number is in radians. #[inline] - fn to_degrees(self) -> f32 { self * (180.0f32 / consts::PI) } + fn to_degrees(self) -> f32 { + self * (180.0f32 / consts::PI) + } /// Converts to radians, assuming the number is in degrees. #[inline] diff --git a/src/libcore/num/f64.rs b/src/libcore/num/f64.rs index 82a09e599e..991a856834 100644 --- a/src/libcore/num/f64.rs +++ b/src/libcore/num/f64.rs @@ -61,13 +61,13 @@ pub const MAX_10_EXP: i32 = 308; /// Not a Number (NaN). #[stable(feature = "rust1", since = "1.0.0")] -pub const NAN: f64 = 0.0_f64/0.0_f64; +pub const NAN: f64 = 0.0_f64 / 0.0_f64; /// Infinity (∞). #[stable(feature = "rust1", since = "1.0.0")] -pub const INFINITY: f64 = 1.0_f64/0.0_f64; +pub const INFINITY: f64 = 1.0_f64 / 0.0_f64; /// Negative infinity (-∞). #[stable(feature = "rust1", since = "1.0.0")] -pub const NEG_INFINITY: f64 = -1.0_f64/0.0_f64; +pub const NEG_INFINITY: f64 = -1.0_f64 / 0.0_f64; /// Basic mathematical constants. #[stable(feature = "rust1", since = "1.0.0")] @@ -144,26 +144,40 @@ pub mod consts { issue = "32110")] impl Float for f64 { #[inline] - fn nan() -> f64 { NAN } + fn nan() -> f64 { + NAN + } #[inline] - fn infinity() -> f64 { INFINITY } + fn infinity() -> f64 { + INFINITY + } #[inline] - fn neg_infinity() -> f64 { NEG_INFINITY } + fn neg_infinity() -> f64 { + NEG_INFINITY + } #[inline] - fn zero() -> f64 { 0.0 } + fn zero() -> f64 { + 0.0 + } #[inline] - fn neg_zero() -> f64 { -0.0 } + fn neg_zero() -> f64 { + -0.0 + } #[inline] - fn one() -> f64 { 1.0 } + fn one() -> f64 { + 1.0 + } /// Returns `true` if the number is NaN. #[inline] - fn is_nan(self) -> bool { self != self } + fn is_nan(self) -> bool { + self != self + } /// Returns `true` if the number is infinite. #[inline] @@ -192,11 +206,11 @@ impl Float for f64 { let bits: u64 = unsafe { mem::transmute(self) }; match (bits & MAN_MASK, bits & EXP_MASK) { - (0, 0) => Fp::Zero, - (_, 0) => Fp::Subnormal, + (0, 0) => Fp::Zero, + (_, 0) => Fp::Subnormal, (0, EXP_MASK) => Fp::Infinite, (_, EXP_MASK) => Fp::Nan, - _ => Fp::Normal, + _ => Fp::Normal, } } @@ -252,7 +266,9 @@ impl Float for f64 { /// Returns the reciprocal (multiplicative inverse) of the number. #[inline] - fn recip(self) -> f64 { 1.0 / self } + fn recip(self) -> f64 { + 1.0 / self + } #[inline] fn powi(self, n: i32) -> f64 { @@ -261,7 +277,9 @@ impl Float for f64 { /// Converts to degrees, assuming the number is in radians. #[inline] - fn to_degrees(self) -> f64 { self * (180.0f64 / consts::PI) } + fn to_degrees(self) -> f64 { + self * (180.0f64 / consts::PI) + } /// Converts to radians, assuming the number is in degrees. #[inline] diff --git a/src/libcore/num/mod.rs b/src/libcore/num/mod.rs index 386daa0846..a4529909e8 100644 --- a/src/libcore/num/mod.rs +++ b/src/libcore/num/mod.rs @@ -43,7 +43,8 @@ use str::FromStr; /// ``` #[stable(feature = "rust1", since = "1.0.0")] #[derive(PartialEq, Eq, PartialOrd, Ord, Clone, Copy, Default, Hash)] -pub struct Wrapping(#[stable(feature = "rust1", since = "1.0.0")] pub T); +pub struct Wrapping(#[stable(feature = "rust1", since = "1.0.0")] + pub T); #[stable(feature = "rust1", since = "1.0.0")] impl fmt::Debug for Wrapping { @@ -516,11 +517,10 @@ macro_rules! int_impl { #[stable(feature = "rust1", since = "1.0.0")] #[inline] pub fn checked_div(self, other: Self) -> Option { - if other == 0 { + if other == 0 || (self == Self::min_value() && other == -1) { None } else { - let (a, b) = self.overflowing_div(other); - if b {None} else {Some(a)} + Some(unsafe { intrinsics::unchecked_div(self, other) }) } } @@ -541,11 +541,10 @@ macro_rules! int_impl { #[stable(feature = "wrapping", since = "1.7.0")] #[inline] pub fn checked_rem(self, other: Self) -> Option { - if other == 0 { + if other == 0 || (self == Self::min_value() && other == -1) { None } else { - let (a, b) = self.overflowing_rem(other); - if b {None} else {Some(a)} + Some(unsafe { intrinsics::unchecked_rem(self, other) }) } } @@ -1688,7 +1687,7 @@ macro_rules! uint_impl { pub fn checked_div(self, other: Self) -> Option { match other { 0 => None, - other => Some(self / other), + other => Some(unsafe { intrinsics::unchecked_div(self, other) }), } } @@ -1709,7 +1708,7 @@ macro_rules! uint_impl { if other == 0 { None } else { - Some(self % other) + Some(unsafe { intrinsics::unchecked_rem(self, other) }) } } @@ -2404,7 +2403,7 @@ pub enum FpCategory { /// Positive or negative infinity. #[stable(feature = "rust1", since = "1.0.0")] - Infinite , + Infinite, /// Positive or negative zero. #[stable(feature = "rust1", since = "1.0.0")] @@ -2570,7 +2569,7 @@ impl fmt::Display for TryFromIntError { macro_rules! same_sign_from_int_impl { ($storage:ty, $target:ty, $($source:ty),*) => {$( - #[stable(feature = "rust1", since = "1.0.0")] + #[unstable(feature = "try_from", issue = "33417")] impl TryFrom<$source> for $target { type Err = TryFromIntError; @@ -2600,7 +2599,7 @@ same_sign_from_int_impl!(i64, isize, i8, i16, i32, i64, isize); macro_rules! cross_sign_from_int_impl { ($unsigned:ty, $($signed:ty),*) => {$( - #[stable(feature = "rust1", since = "1.0.0")] + #[unstable(feature = "try_from", issue = "33417")] impl TryFrom<$unsigned> for $signed { type Err = TryFromIntError; @@ -2614,7 +2613,7 @@ macro_rules! cross_sign_from_int_impl { } } - #[stable(feature = "rust1", since = "1.0.0")] + #[unstable(feature = "try_from", issue = "33417")] impl TryFrom<$signed> for $unsigned { type Err = TryFromIntError; @@ -2664,8 +2663,7 @@ macro_rules! doit { } doit! { i8 i16 i32 i64 isize u8 u16 u32 u64 usize } -fn from_str_radix(src: &str, radix: u32) - -> Result { +fn from_str_radix(src: &str, radix: u32) -> Result { use self::IntErrorKind::*; use self::ParseIntError as PIE; @@ -2688,7 +2686,7 @@ fn from_str_radix(src: &str, radix: u32) let (is_positive, digits) = match src[0] { b'+' => (true, &src[1..]), b'-' if is_signed_ty => (false, &src[1..]), - _ => (true, src) + _ => (true, src), }; if digits.is_empty() { @@ -2740,7 +2738,9 @@ fn from_str_radix(src: &str, radix: u32) /// [`i8::from_str_radix()`]: ../../std/primitive.i8.html#method.from_str_radix #[derive(Debug, Clone, PartialEq, Eq)] #[stable(feature = "rust1", since = "1.0.0")] -pub struct ParseIntError { kind: IntErrorKind } +pub struct ParseIntError { + kind: IntErrorKind, +} #[derive(Debug, Clone, PartialEq, Eq)] enum IntErrorKind { diff --git a/src/libcore/num/wrapping.rs b/src/libcore/num/wrapping.rs index 4857817e84..50d64838a5 100644 --- a/src/libcore/num/wrapping.rs +++ b/src/libcore/num/wrapping.rs @@ -28,7 +28,7 @@ macro_rules! sh_impl_signed { } } - #[stable(feature = "wrapping_impls", since = "1.7.0")] + #[stable(feature = "op_assign_traits", since = "1.8.0")] impl ShlAssign<$f> for Wrapping<$t> { #[inline(always)] fn shl_assign(&mut self, other: $f) { @@ -50,7 +50,7 @@ macro_rules! sh_impl_signed { } } - #[stable(feature = "wrapping_impls", since = "1.7.0")] + #[stable(feature = "op_assign_traits", since = "1.8.0")] impl ShrAssign<$f> for Wrapping<$t> { #[inline(always)] fn shr_assign(&mut self, other: $f) { @@ -72,7 +72,7 @@ macro_rules! sh_impl_unsigned { } } - #[stable(feature = "wrapping_impls", since = "1.7.0")] + #[stable(feature = "op_assign_traits", since = "1.8.0")] impl ShlAssign<$f> for Wrapping<$t> { #[inline(always)] fn shl_assign(&mut self, other: $f) { @@ -90,7 +90,7 @@ macro_rules! sh_impl_unsigned { } } - #[stable(feature = "wrapping_impls", since = "1.7.0")] + #[stable(feature = "op_assign_traits", since = "1.8.0")] impl ShrAssign<$f> for Wrapping<$t> { #[inline(always)] fn shr_assign(&mut self, other: $f) { @@ -131,6 +131,7 @@ macro_rules! wrapping_impl { Wrapping(self.0.wrapping_add(other.0)) } } + forward_ref_binop! { impl Add, add for Wrapping<$t>, Wrapping<$t> } #[stable(feature = "op_assign_traits", since = "1.8.0")] impl AddAssign for Wrapping<$t> { @@ -149,6 +150,7 @@ macro_rules! wrapping_impl { Wrapping(self.0.wrapping_sub(other.0)) } } + forward_ref_binop! { impl Sub, sub for Wrapping<$t>, Wrapping<$t> } #[stable(feature = "op_assign_traits", since = "1.8.0")] impl SubAssign for Wrapping<$t> { @@ -167,6 +169,7 @@ macro_rules! wrapping_impl { Wrapping(self.0.wrapping_mul(other.0)) } } + forward_ref_binop! { impl Mul, mul for Wrapping<$t>, Wrapping<$t> } #[stable(feature = "op_assign_traits", since = "1.8.0")] impl MulAssign for Wrapping<$t> { @@ -185,6 +188,7 @@ macro_rules! wrapping_impl { Wrapping(self.0.wrapping_div(other.0)) } } + forward_ref_binop! { impl Div, div for Wrapping<$t>, Wrapping<$t> } #[stable(feature = "op_assign_traits", since = "1.8.0")] impl DivAssign for Wrapping<$t> { @@ -203,6 +207,7 @@ macro_rules! wrapping_impl { Wrapping(self.0.wrapping_rem(other.0)) } } + forward_ref_binop! { impl Rem, rem for Wrapping<$t>, Wrapping<$t> } #[stable(feature = "op_assign_traits", since = "1.8.0")] impl RemAssign for Wrapping<$t> { @@ -221,6 +226,7 @@ macro_rules! wrapping_impl { Wrapping(!self.0) } } + forward_ref_unop! { impl Not, not for Wrapping<$t> } #[stable(feature = "rust1", since = "1.0.0")] impl BitXor for Wrapping<$t> { @@ -231,6 +237,7 @@ macro_rules! wrapping_impl { Wrapping(self.0 ^ other.0) } } + forward_ref_binop! { impl BitXor, bitxor for Wrapping<$t>, Wrapping<$t> } #[stable(feature = "op_assign_traits", since = "1.8.0")] impl BitXorAssign for Wrapping<$t> { @@ -249,6 +256,7 @@ macro_rules! wrapping_impl { Wrapping(self.0 | other.0) } } + forward_ref_binop! { impl BitOr, bitor for Wrapping<$t>, Wrapping<$t> } #[stable(feature = "op_assign_traits", since = "1.8.0")] impl BitOrAssign for Wrapping<$t> { @@ -267,6 +275,7 @@ macro_rules! wrapping_impl { Wrapping(self.0 & other.0) } } + forward_ref_binop! { impl BitAnd, bitand for Wrapping<$t>, Wrapping<$t> } #[stable(feature = "op_assign_traits", since = "1.8.0")] impl BitAndAssign for Wrapping<$t> { @@ -284,6 +293,7 @@ macro_rules! wrapping_impl { Wrapping(0) - self } } + forward_ref_unop! { impl Neg, neg for Wrapping<$t> } )*) } @@ -310,13 +320,13 @@ mod shift_max { pub const isize: u32 = super::i64; } - pub const i8: u32 = (1 << 3) - 1; + pub const i8: u32 = (1 << 3) - 1; pub const i16: u32 = (1 << 4) - 1; pub const i32: u32 = (1 << 5) - 1; pub const i64: u32 = (1 << 6) - 1; pub use self::platform::isize; - pub const u8: u32 = i8; + pub const u8: u32 = i8; pub const u16: u32 = i16; pub const u32: u32 = i32; pub const u64: u32 = i64; diff --git a/src/libcore/ops.rs b/src/libcore/ops.rs index 85a52da332..07ae5b920b 100644 --- a/src/libcore/ops.rs +++ b/src/libcore/ops.rs @@ -14,7 +14,7 @@ //! //! Some of these traits are imported by the prelude, so they are available in //! every Rust program. Only operators backed by traits can be overloaded. For -//! example, the addition operator (`+`) can be overloaded through the `Add` +//! example, the addition operator (`+`) can be overloaded through the [`Add`] //! trait, but since the assignment operator (`=`) has no backing trait, there //! is no way of overloading its semantics. Additionally, this module does not //! provide any mechanism to create new operators. If traitless overloading or @@ -30,17 +30,18 @@ //! contexts involving built-in types, this is usually not a problem. //! However, using these operators in generic code, requires some //! attention if values have to be reused as opposed to letting the operators -//! consume them. One option is to occasionally use `clone()`. +//! consume them. One option is to occasionally use [`clone()`]. //! Another option is to rely on the types involved providing additional //! operator implementations for references. For example, for a user-defined //! type `T` which is supposed to support addition, it is probably a good -//! idea to have both `T` and `&T` implement the traits `Add` and `Add<&T>` -//! so that generic code can be written without unnecessary cloning. +//! idea to have both `T` and `&T` implement the traits [`Add`][`Add`] and +//! [`Add<&T>`][`Add`] so that generic code can be written without unnecessary +//! cloning. //! //! # Examples //! -//! This example creates a `Point` struct that implements `Add` and `Sub`, and -//! then demonstrates adding and subtracting two `Point`s. +//! This example creates a `Point` struct that implements [`Add`] and [`Sub`], +//! and then demonstrates adding and subtracting two `Point`s. //! //! ```rust //! use std::ops::{Add, Sub}; @@ -75,18 +76,14 @@ //! See the documentation for each trait for an example implementation. //! //! The [`Fn`], [`FnMut`], and [`FnOnce`] traits are implemented by types that can be -//! invoked like functions. Note that `Fn` takes `&self`, `FnMut` takes `&mut -//! self` and `FnOnce` takes `self`. These correspond to the three kinds of +//! invoked like functions. Note that [`Fn`] takes `&self`, [`FnMut`] takes `&mut +//! self` and [`FnOnce`] takes `self`. These correspond to the three kinds of //! methods that can be invoked on an instance: call-by-reference, //! call-by-mutable-reference, and call-by-value. The most common use of these //! traits is to act as bounds to higher-level functions that take functions or //! closures as arguments. //! -//! [`Fn`]: trait.Fn.html -//! [`FnMut`]: trait.FnMut.html -//! [`FnOnce`]: trait.FnOnce.html -//! -//! Taking a `Fn` as a parameter: +//! Taking a [`Fn`] as a parameter: //! //! ```rust //! fn call_with_one(func: F) -> usize @@ -99,7 +96,7 @@ //! assert_eq!(call_with_one(double), 2); //! ``` //! -//! Taking a `FnMut` as a parameter: +//! Taking a [`FnMut`] as a parameter: //! //! ```rust //! fn do_twice(mut func: F) @@ -118,7 +115,7 @@ //! assert_eq!(x, 5); //! ``` //! -//! Taking a `FnOnce` as a parameter: +//! Taking a [`FnOnce`] as a parameter: //! //! ```rust //! fn consume_with_relish(func: F) @@ -140,6 +137,13 @@ //! //! // `consume_and_return_x` can no longer be invoked at this point //! ``` +//! +//! [`Fn`]: trait.Fn.html +//! [`FnMut`]: trait.FnMut.html +//! [`FnOnce`]: trait.FnOnce.html +//! [`Add`]: trait.Add.html +//! [`Sub`]: trait.Sub.html +//! [`clone()`]: ../clone/trait.Clone.html#tymethod.clone #![stable(feature = "rust1", since = "1.0.0")] @@ -178,11 +182,11 @@ pub trait Drop { /// After this function is over, the memory of `self` will be deallocated. /// /// This function cannot be called explicitly. This is compiler error - /// [0040]. However, the [`std::mem::drop`] function in the prelude can be + /// [E0040]. However, the [`std::mem::drop`] function in the prelude can be /// used to call the argument's `Drop` implementation. /// - /// [0040]: https://doc.rust-lang.org/error-index.html#E0040 - /// [`std::mem::drop`]: https://doc.rust-lang.org/std/mem/fn.drop.html + /// [E0040]: ../../error-index.html#E0040 + /// [`std::mem::drop`]: ../../std/mem/fn.drop.html /// /// # Panics /// @@ -192,58 +196,6 @@ pub trait Drop { fn drop(&mut self); } -// implements the unary operator "op &T" -// based on "op T" where T is expected to be `Copy`able -macro_rules! forward_ref_unop { - (impl $imp:ident, $method:ident for $t:ty) => { - #[stable(feature = "rust1", since = "1.0.0")] - impl<'a> $imp for &'a $t { - type Output = <$t as $imp>::Output; - - #[inline] - fn $method(self) -> <$t as $imp>::Output { - $imp::$method(*self) - } - } - } -} - -// implements binary operators "&T op U", "T op &U", "&T op &U" -// based on "T op U" where T and U are expected to be `Copy`able -macro_rules! forward_ref_binop { - (impl $imp:ident, $method:ident for $t:ty, $u:ty) => { - #[stable(feature = "rust1", since = "1.0.0")] - impl<'a> $imp<$u> for &'a $t { - type Output = <$t as $imp<$u>>::Output; - - #[inline] - fn $method(self, other: $u) -> <$t as $imp<$u>>::Output { - $imp::$method(*self, other) - } - } - - #[stable(feature = "rust1", since = "1.0.0")] - impl<'a> $imp<&'a $u> for $t { - type Output = <$t as $imp<$u>>::Output; - - #[inline] - fn $method(self, other: &'a $u) -> <$t as $imp<$u>>::Output { - $imp::$method(self, *other) - } - } - - #[stable(feature = "rust1", since = "1.0.0")] - impl<'a, 'b> $imp<&'a $u> for &'b $t { - type Output = <$t as $imp<$u>>::Output; - - #[inline] - fn $method(self, other: &'a $u) -> <$t as $imp<$u>>::Output { - $imp::$method(*self, *other) - } - } - } -} - /// The `Add` trait is used to specify the functionality of `+`. /// /// # Examples @@ -1641,7 +1593,7 @@ rem_assign_impl! { usize u8 u16 u32 u64 isize i8 i16 i32 i64 f32 f64 } #[lang = "bitand_assign"] #[stable(feature = "op_assign_traits", since = "1.8.0")] pub trait BitAndAssign { - /// The method for the `&` operator + /// The method for the `&=` operator #[stable(feature = "op_assign_traits", since = "1.8.0")] fn bitand_assign(&mut self, Rhs); } @@ -1873,12 +1825,20 @@ macro_rules! shr_assign_impl_all { shr_assign_impl_all! { u8 u16 u32 u64 usize i8 i16 i32 i64 isize } /// The `Index` trait is used to specify the functionality of indexing operations -/// like `arr[idx]` when used in an immutable context. +/// like `container[index]` when used in an immutable context. +/// +/// `container[index]` is actually syntactic sugar for `*container.index(index)`, +/// but only when used as an immutable value. If a mutable value is requested, +/// [`IndexMut`] is used instead. This allows nice things such as +/// `let value = v[index]` if `value` implements [`Copy`]. +/// +/// [`IndexMut`]: ../../std/ops/trait.IndexMut.html +/// [`Copy`]: ../../std/marker/trait.Copy.html /// /// # Examples /// -/// This example implements `Index` on a read-only `NucleotideCount` container, -/// enabling individual counts to be retrieved with index syntax. +/// The following example implements `Index` on a read-only `NucleotideCount` +/// container, enabling individual counts to be retrieved with index syntax. /// /// ``` /// use std::ops::Index; @@ -1924,50 +1884,91 @@ pub trait Index { #[stable(feature = "rust1", since = "1.0.0")] type Output: ?Sized; - /// The method for the indexing (`Foo[Bar]`) operation + /// The method for the indexing (`container[index]`) operation #[stable(feature = "rust1", since = "1.0.0")] fn index(&self, index: Idx) -> &Self::Output; } /// The `IndexMut` trait is used to specify the functionality of indexing -/// operations like `arr[idx]`, when used in a mutable context. +/// operations like `container[index]` when used in a mutable context. +/// +/// `container[index]` is actually syntactic sugar for +/// `*container.index_mut(index)`, but only when used as a mutable value. If +/// an immutable value is requested, the [`Index`] trait is used instead. This +/// allows nice things such as `v[index] = value` if `value` implements [`Copy`]. +/// +/// [`Index`]: ../../std/ops/trait.Index.html +/// [`Copy`]: ../../std/marker/trait.Copy.html /// /// # Examples /// -/// A trivial implementation of `IndexMut`. When `Foo[Bar]` happens, it ends up -/// calling `index_mut`, and therefore, `main` prints `Indexing!`. +/// A very simple implementation of a `Balance` struct that has two sides, where +/// each can be indexed mutably and immutably. /// /// ``` -/// use std::ops::{Index, IndexMut}; +/// use std::ops::{Index,IndexMut}; /// -/// #[derive(Copy, Clone)] -/// struct Foo; -/// struct Bar; +/// #[derive(Debug)] +/// enum Side { +/// Left, +/// Right, +/// } /// -/// impl Index for Foo { -/// type Output = Foo; +/// #[derive(Debug, PartialEq)] +/// enum Weight { +/// Kilogram(f32), +/// Pound(f32), +/// } +/// +/// struct Balance { +/// pub left: Weight, +/// pub right:Weight, +/// } /// -/// fn index<'a>(&'a self, _index: Bar) -> &'a Foo { -/// self +/// impl Index for Balance { +/// type Output = Weight; +/// +/// fn index<'a>(&'a self, index: Side) -> &'a Weight { +/// println!("Accessing {:?}-side of balance immutably", index); +/// match index { +/// Side::Left => &self.left, +/// Side::Right => &self.right, +/// } /// } /// } /// -/// impl IndexMut for Foo { -/// fn index_mut<'a>(&'a mut self, _index: Bar) -> &'a mut Foo { -/// println!("Indexing!"); -/// self +/// impl IndexMut for Balance { +/// fn index_mut<'a>(&'a mut self, index: Side) -> &'a mut Weight { +/// println!("Accessing {:?}-side of balance mutably", index); +/// match index { +/// Side::Left => &mut self.left, +/// Side::Right => &mut self.right, +/// } /// } /// } /// /// fn main() { -/// &mut Foo[Bar]; +/// let mut balance = Balance { +/// right: Weight::Kilogram(2.5), +/// left: Weight::Pound(1.5), +/// }; +/// +/// // In this case balance[Side::Right] is sugar for +/// // *balance.index(Side::Right), since we are only reading +/// // balance[Side::Right], not writing it. +/// assert_eq!(balance[Side::Right],Weight::Kilogram(2.5)); +/// +/// // However in this case balance[Side::Left] is sugar for +/// // *balance.index_mut(Side::Left), since we are writing +/// // balance[Side::Left]. +/// balance[Side::Left] = Weight::Kilogram(3.0); /// } /// ``` #[lang = "index_mut"] #[rustc_on_unimplemented = "the type `{Self}` cannot be mutably indexed by `{Idx}`"] #[stable(feature = "rust1", since = "1.0.0")] pub trait IndexMut: Index { - /// The method for the indexing (`Foo[Bar]`) operation + /// The method for the mutable indexing (`container[index]`) operation #[stable(feature = "rust1", since = "1.0.0")] fn index_mut(&mut self, index: Idx) -> &mut Self::Output; } @@ -2431,13 +2432,13 @@ impl<'a, T: ?Sized> Deref for &'a mut T { /// impl Deref for DerefMutExample { /// type Target = T; /// -/// fn deref<'a>(&'a self) -> &'a T { +/// fn deref(&self) -> &T { /// &self.value /// } /// } /// /// impl DerefMut for DerefMutExample { -/// fn deref_mut<'a>(&'a mut self) -> &'a mut T { +/// fn deref_mut(&mut self) -> &mut T { /// &mut self.value /// } /// } diff --git a/src/libcore/option.rs b/src/libcore/option.rs index cb18feff73..607e16887a 100644 --- a/src/libcore/option.rs +++ b/src/libcore/option.rs @@ -145,7 +145,7 @@ #![stable(feature = "rust1", since = "1.0.0")] -use iter::{FromIterator, FusedIterator}; +use iter::{FromIterator, FusedIterator, TrustedLen}; use mem; // Note that this is not a lang item per se, but it has a hidden dependency on @@ -803,6 +803,7 @@ impl DoubleEndedIterator for Item { impl ExactSizeIterator for Item {} impl FusedIterator for Item {} +unsafe impl TrustedLen for Item {} /// An iterator over a reference of the contained item in an [`Option`]. /// @@ -833,6 +834,9 @@ impl<'a, A> ExactSizeIterator for Iter<'a, A> {} #[unstable(feature = "fused", issue = "35602")] impl<'a, A> FusedIterator for Iter<'a, A> {} +#[unstable(feature = "trusted_len", issue = "37572")] +unsafe impl<'a, A> TrustedLen for Iter<'a, A> {} + #[stable(feature = "rust1", since = "1.0.0")] impl<'a, A> Clone for Iter<'a, A> { fn clone(&self) -> Iter<'a, A> { @@ -868,6 +872,8 @@ impl<'a, A> ExactSizeIterator for IterMut<'a, A> {} #[unstable(feature = "fused", issue = "35602")] impl<'a, A> FusedIterator for IterMut<'a, A> {} +#[unstable(feature = "trusted_len", issue = "37572")] +unsafe impl<'a, A> TrustedLen for IterMut<'a, A> {} /// An iterator over the item contained inside an [`Option`]. /// @@ -898,6 +904,9 @@ impl ExactSizeIterator for IntoIter {} #[unstable(feature = "fused", issue = "35602")] impl FusedIterator for IntoIter {} +#[unstable(feature = "trusted_len", issue = "37572")] +unsafe impl TrustedLen for IntoIter {} + ///////////////////////////////////////////////////////////////////////////// // FromIterator ///////////////////////////////////////////////////////////////////////////// @@ -914,12 +923,12 @@ impl> FromIterator> for Option { /// ``` /// use std::u16; /// - /// let v = vec!(1, 2); + /// let v = vec![1, 2]; /// let res: Option> = v.iter().map(|&x: &u16| /// if x == u16::MAX { None } /// else { Some(x + 1) } /// ).collect(); - /// assert!(res == Some(vec!(2, 3))); + /// assert!(res == Some(vec![2, 3])); /// ``` #[inline] fn from_iter>>(iter: I) -> Option { diff --git a/src/libcore/prelude/v1.rs b/src/libcore/prelude/v1.rs index 75db6fceab..3fa6a97d4c 100644 --- a/src/libcore/prelude/v1.rs +++ b/src/libcore/prelude/v1.rs @@ -18,36 +18,50 @@ // Reexported core operators #[stable(feature = "core_prelude", since = "1.4.0")] -#[doc(no_inline)] pub use marker::{Copy, Send, Sized, Sync}; +#[doc(no_inline)] +pub use marker::{Copy, Send, Sized, Sync}; #[stable(feature = "core_prelude", since = "1.4.0")] -#[doc(no_inline)] pub use ops::{Drop, Fn, FnMut, FnOnce}; +#[doc(no_inline)] +pub use ops::{Drop, Fn, FnMut, FnOnce}; // Reexported functions #[stable(feature = "core_prelude", since = "1.4.0")] -#[doc(no_inline)] pub use mem::drop; +#[doc(no_inline)] +pub use mem::drop; // Reexported types and traits #[stable(feature = "core_prelude", since = "1.4.0")] -#[doc(no_inline)] pub use clone::Clone; +#[doc(no_inline)] +pub use clone::Clone; #[stable(feature = "core_prelude", since = "1.4.0")] -#[doc(no_inline)] pub use cmp::{PartialEq, PartialOrd, Eq, Ord}; +#[doc(no_inline)] +pub use cmp::{PartialEq, PartialOrd, Eq, Ord}; #[stable(feature = "core_prelude", since = "1.4.0")] -#[doc(no_inline)] pub use convert::{AsRef, AsMut, Into, From}; +#[doc(no_inline)] +pub use convert::{AsRef, AsMut, Into, From}; #[stable(feature = "core_prelude", since = "1.4.0")] -#[doc(no_inline)] pub use default::Default; +#[doc(no_inline)] +pub use default::Default; #[stable(feature = "core_prelude", since = "1.4.0")] -#[doc(no_inline)] pub use iter::{Iterator, Extend, IntoIterator}; +#[doc(no_inline)] +pub use iter::{Iterator, Extend, IntoIterator}; #[stable(feature = "core_prelude", since = "1.4.0")] -#[doc(no_inline)] pub use iter::{DoubleEndedIterator, ExactSizeIterator}; +#[doc(no_inline)] +pub use iter::{DoubleEndedIterator, ExactSizeIterator}; #[stable(feature = "core_prelude", since = "1.4.0")] -#[doc(no_inline)] pub use option::Option::{self, Some, None}; +#[doc(no_inline)] +pub use option::Option::{self, Some, None}; #[stable(feature = "core_prelude", since = "1.4.0")] -#[doc(no_inline)] pub use result::Result::{self, Ok, Err}; +#[doc(no_inline)] +pub use result::Result::{self, Ok, Err}; // Reexported extension traits for primitive types #[stable(feature = "core_prelude", since = "1.4.0")] -#[doc(no_inline)] pub use slice::SliceExt; +#[doc(no_inline)] +pub use slice::SliceExt; #[stable(feature = "core_prelude", since = "1.4.0")] -#[doc(no_inline)] pub use str::StrExt; +#[doc(no_inline)] +pub use str::StrExt; #[stable(feature = "core_prelude", since = "1.4.0")] -#[doc(no_inline)] pub use char::CharExt; +#[doc(no_inline)] +pub use char::CharExt; diff --git a/src/libcore/ptr.rs b/src/libcore/ptr.rs index 69682652a6..2ad38de72b 100644 --- a/src/libcore/ptr.rs +++ b/src/libcore/ptr.rs @@ -344,6 +344,46 @@ impl *const T { pub unsafe fn offset(self, count: isize) -> *const T where T: Sized { intrinsics::offset(self, count) } + + /// Calculates the offset from a pointer using wrapping arithmetic. + /// `count` is in units of T; e.g. a `count` of 3 represents a pointer + /// offset of `3 * sizeof::()` bytes. + /// + /// # Safety + /// + /// The resulting pointer does not need to be in bounds, but it is + /// potentially hazardous to dereference (which requires `unsafe`). + /// + /// Always use `.offset(count)` instead when possible, because `offset` + /// allows the compiler to optimize better. + /// + /// # Examples + /// + /// Basic usage: + /// + /// ``` + /// #![feature(ptr_wrapping_offset)] + /// // Iterate using a raw pointer in increments of two elements + /// let data = [1u8, 2, 3, 4, 5]; + /// let mut ptr: *const u8 = data.as_ptr(); + /// let step = 2; + /// let end_rounded_up = ptr.wrapping_offset(6); + /// + /// // This loop prints "1, 3, 5, " + /// while ptr != end_rounded_up { + /// unsafe { + /// print!("{}, ", *ptr); + /// } + /// ptr = ptr.wrapping_offset(step); + /// } + /// ``` + #[unstable(feature = "ptr_wrapping_offset", issue = "37570")] + #[inline] + pub fn wrapping_offset(self, count: isize) -> *const T where T: Sized { + unsafe { + intrinsics::arith_offset(self, count) + } + } } #[lang = "mut_ptr"] @@ -429,6 +469,46 @@ impl *mut T { intrinsics::offset(self, count) as *mut T } + /// Calculates the offset from a pointer using wrapping arithmetic. + /// `count` is in units of T; e.g. a `count` of 3 represents a pointer + /// offset of `3 * sizeof::()` bytes. + /// + /// # Safety + /// + /// The resulting pointer does not need to be in bounds, but it is + /// potentially hazardous to dereference (which requires `unsafe`). + /// + /// Always use `.offset(count)` instead when possible, because `offset` + /// allows the compiler to optimize better. + /// + /// # Examples + /// + /// Basic usage: + /// + /// ``` + /// #![feature(ptr_wrapping_offset)] + /// // Iterate using a raw pointer in increments of two elements + /// let mut data = [1u8, 2, 3, 4, 5]; + /// let mut ptr: *mut u8 = data.as_mut_ptr(); + /// let step = 2; + /// let end_rounded_up = ptr.wrapping_offset(6); + /// + /// while ptr != end_rounded_up { + /// unsafe { + /// *ptr = 0; + /// } + /// ptr = ptr.wrapping_offset(step); + /// } + /// assert_eq!(&data, &[0, 2, 0, 4, 0]); + /// ``` + #[unstable(feature = "ptr_wrapping_offset", issue = "37570")] + #[inline] + pub fn wrapping_offset(self, count: isize) -> *mut T where T: Sized { + unsafe { + intrinsics::arith_offset(self, count) as *mut T + } + } + /// Returns `None` if the pointer is null, or else returns a mutable /// reference to the value wrapped in `Some`. /// @@ -761,7 +841,7 @@ impl Deref for Unique { } } -#[stable(feature = "rust1", since = "1.0.0")] +#[unstable(feature = "unique", issue = "27730")] 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/result.rs b/src/libcore/result.rs index 9684525929..afed99d265 100644 --- a/src/libcore/result.rs +++ b/src/libcore/result.rs @@ -249,7 +249,7 @@ #![stable(feature = "rust1", since = "1.0.0")] use fmt; -use iter::{FromIterator, FusedIterator}; +use iter::{FromIterator, FusedIterator, TrustedLen}; /// `Result` is a type that represents either success (`Ok`) or failure (`Err`). /// @@ -792,6 +792,44 @@ impl Result { } } +impl Result { + /// Returns the contained value or a default + /// + /// Consumes the `self` argument then, if `Ok`, returns the contained + /// value, otherwise if `Err`, returns the default value for that + /// type. + /// + /// # Examples + /// + /// Convert a string to an integer, turning poorly-formed strings + /// into 0 (the default value for integers). [`parse`] converts + /// a string to any other type that implements [`FromStr`], returning an + /// `Err` on error. + /// + /// ``` + /// #![feature(result_unwrap_or_default)] + /// + /// let good_year_from_input = "1909"; + /// let bad_year_from_input = "190blarg"; + /// let good_year = good_year_from_input.parse().unwrap_or_default(); + /// let bad_year = bad_year_from_input.parse().unwrap_or_default(); + /// + /// assert_eq!(1909, good_year); + /// assert_eq!(0, bad_year); + /// + /// [`parse`]: ../../std/primitive.str.html#method.parse + /// [`FromStr`]: ../../std/str/trait.FromStr.html + /// ``` + #[inline] + #[unstable(feature = "result_unwrap_or_default", issue = "37516")] + pub fn unwrap_or_default(self) -> T { + match self { + Ok(x) => x, + Err(_) => Default::default(), + } + } +} + // This is a separate function to reduce the code size of the methods #[inline(never)] #[cold] @@ -886,6 +924,9 @@ impl<'a, T> ExactSizeIterator for Iter<'a, T> {} #[unstable(feature = "fused", issue = "35602")] impl<'a, T> FusedIterator for Iter<'a, T> {} +#[unstable(feature = "trusted_len", issue = "37572")] +unsafe impl<'a, A> TrustedLen for Iter<'a, A> {} + #[stable(feature = "rust1", since = "1.0.0")] impl<'a, T> Clone for Iter<'a, T> { fn clone(&self) -> Iter<'a, T> { Iter { inner: self.inner } } @@ -924,6 +965,9 @@ impl<'a, T> ExactSizeIterator for IterMut<'a, T> {} #[unstable(feature = "fused", issue = "35602")] impl<'a, T> FusedIterator for IterMut<'a, T> {} +#[unstable(feature = "trusted_len", issue = "37572")] +unsafe impl<'a, A> TrustedLen for IterMut<'a, A> {} + /// An iterator over the value in a [`Ok`] variant of a [`Result`]. This struct is /// created by the [`into_iter`] method on [`Result`][`Result`] (provided by /// the [`IntoIterator`] trait). @@ -961,6 +1005,9 @@ impl ExactSizeIterator for IntoIter {} #[unstable(feature = "fused", issue = "35602")] impl FusedIterator for IntoIter {} +#[unstable(feature = "trusted_len", issue = "37572")] +unsafe impl TrustedLen for IntoIter {} + ///////////////////////////////////////////////////////////////////////////// // FromIterator ///////////////////////////////////////////////////////////////////////////// @@ -977,12 +1024,12 @@ impl> FromIterator> for Result { /// ``` /// use std::u32; /// - /// let v = vec!(1, 2); + /// let v = vec![1, 2]; /// let res: Result, &'static str> = v.iter().map(|&x: &u32| /// if x == u32::MAX { Err("Overflow!") } /// else { Ok(x + 1) } /// ).collect(); - /// assert!(res == Ok(vec!(2, 3))); + /// assert!(res == Ok(vec![2, 3])); /// ``` #[inline] fn from_iter>>(iter: I) -> Result { @@ -1008,6 +1055,11 @@ impl> FromIterator> for Result { None => None, } } + + fn size_hint(&self) -> (usize, Option) { + let (_min, max) = self.iter.size_hint(); + (0, max) + } } let mut adapter = Adapter { iter: iter.into_iter(), err: None }; diff --git a/src/libcore/slice.rs b/src/libcore/slice.rs index d1df56905d..871b63145c 100644 --- a/src/libcore/slice.rs +++ b/src/libcore/slice.rs @@ -988,6 +988,9 @@ impl<'a, T> ExactSizeIterator for Iter<'a, T> {} #[unstable(feature = "fused", issue = "35602")] impl<'a, T> FusedIterator for Iter<'a, T> {} +#[unstable(feature = "trusted_len", issue = "37572")] +unsafe impl<'a, T> TrustedLen for Iter<'a, T> {} + #[stable(feature = "rust1", since = "1.0.0")] impl<'a, T> Clone for Iter<'a, T> { fn clone(&self) -> Iter<'a, T> { Iter { ptr: self.ptr, end: self.end, _marker: self._marker } } @@ -1109,6 +1112,9 @@ impl<'a, T> ExactSizeIterator for IterMut<'a, T> {} #[unstable(feature = "fused", issue = "35602")] impl<'a, T> FusedIterator for IterMut<'a, T> {} +#[unstable(feature = "trusted_len", issue = "37572")] +unsafe impl<'a, T> TrustedLen for IterMut<'a, T> {} + /// An internal abstraction over the splitting iterators, so that /// splitn, splitn_mut etc can be implemented once. #[doc(hidden)] @@ -1968,6 +1974,7 @@ unsafe impl<'a, T> TrustedRandomAccess for Iter<'a, T> { unsafe fn get_unchecked(&mut self, i: usize) -> &'a T { &*self.ptr.offset(i as isize) } + fn may_have_side_effect() -> bool { false } } #[doc(hidden)] @@ -1975,4 +1982,5 @@ unsafe impl<'a, T> TrustedRandomAccess for IterMut<'a, T> { unsafe fn get_unchecked(&mut self, i: usize) -> &'a mut T { &mut *self.ptr.offset(i as isize) } + fn may_have_side_effect() -> bool { false } } diff --git a/src/libcore/str/mod.rs b/src/libcore/str/mod.rs index d63d2d64fe..196750254a 100644 --- a/src/libcore/str/mod.rs +++ b/src/libcore/str/mod.rs @@ -132,7 +132,7 @@ impl Utf8Error { /// verified. /// /// It is the maximum index such that `from_utf8(input[..index])` - /// would return `Some(_)`. + /// would return `Ok(_)`. /// /// # Examples /// diff --git a/src/libcore/sync/atomic.rs b/src/libcore/sync/atomic.rs index f5f37be52d..c10f7e39fc 100644 --- a/src/libcore/sync/atomic.rs +++ b/src/libcore/sync/atomic.rs @@ -95,7 +95,7 @@ pub struct AtomicBool { #[cfg(target_has_atomic = "8")] #[stable(feature = "rust1", since = "1.0.0")] impl Default for AtomicBool { - /// Creates an `AtomicBool` initialised as false. + /// Creates an `AtomicBool` initialized to `false`. fn default() -> Self { Self::new(false) } @@ -166,6 +166,10 @@ pub enum Ordering { /// sequentially consistent operations in the same order. #[stable(feature = "rust1", since = "1.0.0")] SeqCst, + // Prevent exhaustive matching to allow for future extension + #[doc(hidden)] + #[unstable(feature = "future_atomic_orderings", issue = "0")] + __Nonexhaustive, } /// An `AtomicBool` initialized to `false`. @@ -277,7 +281,9 @@ impl AtomicBool { #[inline] #[stable(feature = "rust1", since = "1.0.0")] pub fn store(&self, val: bool, order: Ordering) { - unsafe { atomic_store(self.v.get(), val as u8, order); } + unsafe { + atomic_store(self.v.get(), val as u8, order); + } } /// Stores a value into the bool, returning the old value. @@ -366,9 +372,11 @@ impl AtomicBool { current: bool, new: bool, success: Ordering, - failure: Ordering) -> Result { - match unsafe { atomic_compare_exchange(self.v.get(), current as u8, new as u8, - success, failure) } { + failure: Ordering) + -> Result { + match unsafe { + atomic_compare_exchange(self.v.get(), current as u8, new as u8, success, failure) + } { Ok(x) => Ok(x != 0), Err(x) => Err(x != 0), } @@ -409,9 +417,11 @@ impl AtomicBool { current: bool, new: bool, success: Ordering, - failure: Ordering) -> Result { - match unsafe { atomic_compare_exchange_weak(self.v.get(), current as u8, new as u8, - success, failure) } { + failure: Ordering) + -> Result { + match unsafe { + atomic_compare_exchange_weak(self.v.get(), current as u8, new as u8, success, failure) + } { Ok(x) => Ok(x != 0), Err(x) => Err(x != 0), } @@ -632,9 +642,7 @@ impl AtomicPtr { #[inline] #[stable(feature = "rust1", since = "1.0.0")] pub fn load(&self, order: Ordering) -> *mut T { - unsafe { - atomic_load(self.p.get() as *mut usize, order) as *mut T - } + unsafe { atomic_load(self.p.get() as *mut usize, order) as *mut T } } /// Stores a value into the pointer. @@ -660,7 +668,9 @@ impl AtomicPtr { #[inline] #[stable(feature = "rust1", since = "1.0.0")] pub fn store(&self, ptr: *mut T, order: Ordering) { - unsafe { atomic_store(self.p.get() as *mut usize, ptr as usize, order); } + unsafe { + atomic_store(self.p.get() as *mut usize, ptr as usize, order); + } } /// Stores a value into the pointer, returning the old value. @@ -745,7 +755,8 @@ impl AtomicPtr { current: *mut T, new: *mut T, success: Ordering, - failure: Ordering) -> Result<*mut T, *mut T> { + failure: Ordering) + -> Result<*mut T, *mut T> { unsafe { let res = atomic_compare_exchange(self.p.get() as *mut usize, current as usize, @@ -794,7 +805,8 @@ impl AtomicPtr { current: *mut T, new: *mut T, success: Ordering, - failure: Ordering) -> Result<*mut T, *mut T> { + failure: Ordering) + -> Result<*mut T, *mut T> { unsafe { let res = atomic_compare_exchange_weak(self.p.get() as *mut usize, current as usize, @@ -1266,9 +1278,10 @@ fn strongest_failure_ordering(order: Ordering) -> Ordering { match order { Release => Relaxed, Relaxed => Relaxed, - SeqCst => SeqCst, + SeqCst => SeqCst, Acquire => Acquire, - AcqRel => Acquire, + AcqRel => Acquire, + __Nonexhaustive => __Nonexhaustive, } } @@ -1277,9 +1290,10 @@ unsafe fn atomic_store(dst: *mut T, val: T, order: Ordering) { match order { Release => intrinsics::atomic_store_rel(dst, val), Relaxed => intrinsics::atomic_store_relaxed(dst, val), - SeqCst => intrinsics::atomic_store(dst, val), + SeqCst => intrinsics::atomic_store(dst, val), Acquire => panic!("there is no such thing as an acquire store"), - AcqRel => panic!("there is no such thing as an acquire/release store"), + AcqRel => panic!("there is no such thing as an acquire/release store"), + __Nonexhaustive => panic!("invalid memory ordering"), } } @@ -1288,9 +1302,10 @@ unsafe fn atomic_load(dst: *const T, order: Ordering) -> T { match order { Acquire => intrinsics::atomic_load_acq(dst), Relaxed => intrinsics::atomic_load_relaxed(dst), - SeqCst => intrinsics::atomic_load(dst), + SeqCst => intrinsics::atomic_load(dst), Release => panic!("there is no such thing as a release load"), - AcqRel => panic!("there is no such thing as an acquire/release load"), + AcqRel => panic!("there is no such thing as an acquire/release load"), + __Nonexhaustive => panic!("invalid memory ordering"), } } @@ -1299,9 +1314,10 @@ unsafe fn atomic_swap(dst: *mut T, val: T, order: Ordering) -> T { match order { Acquire => intrinsics::atomic_xchg_acq(dst, val), Release => intrinsics::atomic_xchg_rel(dst, val), - AcqRel => intrinsics::atomic_xchg_acqrel(dst, val), + AcqRel => intrinsics::atomic_xchg_acqrel(dst, val), Relaxed => intrinsics::atomic_xchg_relaxed(dst, val), - SeqCst => intrinsics::atomic_xchg(dst, val) + SeqCst => intrinsics::atomic_xchg(dst, val), + __Nonexhaustive => panic!("invalid memory ordering"), } } @@ -1311,9 +1327,10 @@ unsafe fn atomic_add(dst: *mut T, val: T, order: Ordering) -> T { match order { Acquire => intrinsics::atomic_xadd_acq(dst, val), Release => intrinsics::atomic_xadd_rel(dst, val), - AcqRel => intrinsics::atomic_xadd_acqrel(dst, val), + AcqRel => intrinsics::atomic_xadd_acqrel(dst, val), Relaxed => intrinsics::atomic_xadd_relaxed(dst, val), - SeqCst => intrinsics::atomic_xadd(dst, val) + SeqCst => intrinsics::atomic_xadd(dst, val), + __Nonexhaustive => panic!("invalid memory ordering"), } } @@ -1323,9 +1340,10 @@ unsafe fn atomic_sub(dst: *mut T, val: T, order: Ordering) -> T { match order { Acquire => intrinsics::atomic_xsub_acq(dst, val), Release => intrinsics::atomic_xsub_rel(dst, val), - AcqRel => intrinsics::atomic_xsub_acqrel(dst, val), + AcqRel => intrinsics::atomic_xsub_acqrel(dst, val), Relaxed => intrinsics::atomic_xsub_relaxed(dst, val), - SeqCst => intrinsics::atomic_xsub(dst, val) + SeqCst => intrinsics::atomic_xsub(dst, val), + __Nonexhaustive => panic!("invalid memory ordering"), } } @@ -1334,26 +1352,25 @@ unsafe fn atomic_compare_exchange(dst: *mut T, old: T, new: T, success: Ordering, - failure: Ordering) -> Result { + failure: Ordering) + -> Result { let (val, ok) = match (success, failure) { (Acquire, Acquire) => intrinsics::atomic_cxchg_acq(dst, old, new), (Release, Relaxed) => intrinsics::atomic_cxchg_rel(dst, old, new), - (AcqRel, Acquire) => intrinsics::atomic_cxchg_acqrel(dst, old, new), + (AcqRel, Acquire) => intrinsics::atomic_cxchg_acqrel(dst, old, new), (Relaxed, Relaxed) => intrinsics::atomic_cxchg_relaxed(dst, old, new), - (SeqCst, SeqCst) => intrinsics::atomic_cxchg(dst, old, new), + (SeqCst, SeqCst) => intrinsics::atomic_cxchg(dst, old, new), (Acquire, Relaxed) => intrinsics::atomic_cxchg_acq_failrelaxed(dst, old, new), - (AcqRel, Relaxed) => intrinsics::atomic_cxchg_acqrel_failrelaxed(dst, old, new), - (SeqCst, Relaxed) => intrinsics::atomic_cxchg_failrelaxed(dst, old, new), - (SeqCst, Acquire) => intrinsics::atomic_cxchg_failacq(dst, old, new), + (AcqRel, Relaxed) => intrinsics::atomic_cxchg_acqrel_failrelaxed(dst, old, new), + (SeqCst, Relaxed) => intrinsics::atomic_cxchg_failrelaxed(dst, old, new), + (SeqCst, Acquire) => intrinsics::atomic_cxchg_failacq(dst, old, new), + (__Nonexhaustive, _) => panic!("invalid memory ordering"), + (_, __Nonexhaustive) => panic!("invalid memory ordering"), (_, AcqRel) => panic!("there is no such thing as an acquire/release failure ordering"), (_, Release) => panic!("there is no such thing as a release failure ordering"), _ => panic!("a failure ordering can't be stronger than a success ordering"), }; - if ok { - Ok(val) - } else { - Err(val) - } + if ok { Ok(val) } else { Err(val) } } #[inline] @@ -1361,26 +1378,25 @@ unsafe fn atomic_compare_exchange_weak(dst: *mut T, old: T, new: T, success: Ordering, - failure: Ordering) -> Result { + failure: Ordering) + -> Result { let (val, ok) = match (success, failure) { (Acquire, Acquire) => intrinsics::atomic_cxchgweak_acq(dst, old, new), (Release, Relaxed) => intrinsics::atomic_cxchgweak_rel(dst, old, new), - (AcqRel, Acquire) => intrinsics::atomic_cxchgweak_acqrel(dst, old, new), + (AcqRel, Acquire) => intrinsics::atomic_cxchgweak_acqrel(dst, old, new), (Relaxed, Relaxed) => intrinsics::atomic_cxchgweak_relaxed(dst, old, new), - (SeqCst, SeqCst) => intrinsics::atomic_cxchgweak(dst, old, new), + (SeqCst, SeqCst) => intrinsics::atomic_cxchgweak(dst, old, new), (Acquire, Relaxed) => intrinsics::atomic_cxchgweak_acq_failrelaxed(dst, old, new), - (AcqRel, Relaxed) => intrinsics::atomic_cxchgweak_acqrel_failrelaxed(dst, old, new), - (SeqCst, Relaxed) => intrinsics::atomic_cxchgweak_failrelaxed(dst, old, new), - (SeqCst, Acquire) => intrinsics::atomic_cxchgweak_failacq(dst, old, new), + (AcqRel, Relaxed) => intrinsics::atomic_cxchgweak_acqrel_failrelaxed(dst, old, new), + (SeqCst, Relaxed) => intrinsics::atomic_cxchgweak_failrelaxed(dst, old, new), + (SeqCst, Acquire) => intrinsics::atomic_cxchgweak_failacq(dst, old, new), + (__Nonexhaustive, _) => panic!("invalid memory ordering"), + (_, __Nonexhaustive) => panic!("invalid memory ordering"), (_, AcqRel) => panic!("there is no such thing as an acquire/release failure ordering"), (_, Release) => panic!("there is no such thing as a release failure ordering"), _ => panic!("a failure ordering can't be stronger than a success ordering"), }; - if ok { - Ok(val) - } else { - Err(val) - } + if ok { Ok(val) } else { Err(val) } } #[inline] @@ -1388,9 +1404,10 @@ unsafe fn atomic_and(dst: *mut T, val: T, order: Ordering) -> T { match order { Acquire => intrinsics::atomic_and_acq(dst, val), Release => intrinsics::atomic_and_rel(dst, val), - AcqRel => intrinsics::atomic_and_acqrel(dst, val), + AcqRel => intrinsics::atomic_and_acqrel(dst, val), Relaxed => intrinsics::atomic_and_relaxed(dst, val), - SeqCst => intrinsics::atomic_and(dst, val) + SeqCst => intrinsics::atomic_and(dst, val), + __Nonexhaustive => panic!("invalid memory ordering"), } } @@ -1399,9 +1416,10 @@ unsafe fn atomic_or(dst: *mut T, val: T, order: Ordering) -> T { match order { Acquire => intrinsics::atomic_or_acq(dst, val), Release => intrinsics::atomic_or_rel(dst, val), - AcqRel => intrinsics::atomic_or_acqrel(dst, val), + AcqRel => intrinsics::atomic_or_acqrel(dst, val), Relaxed => intrinsics::atomic_or_relaxed(dst, val), - SeqCst => intrinsics::atomic_or(dst, val) + SeqCst => intrinsics::atomic_or(dst, val), + __Nonexhaustive => panic!("invalid memory ordering"), } } @@ -1410,9 +1428,10 @@ unsafe fn atomic_xor(dst: *mut T, val: T, order: Ordering) -> T { match order { Acquire => intrinsics::atomic_xor_acq(dst, val), Release => intrinsics::atomic_xor_rel(dst, val), - AcqRel => intrinsics::atomic_xor_acqrel(dst, val), + AcqRel => intrinsics::atomic_xor_acqrel(dst, val), Relaxed => intrinsics::atomic_xor_relaxed(dst, val), - SeqCst => intrinsics::atomic_xor(dst, val) + SeqCst => intrinsics::atomic_xor(dst, val), + __Nonexhaustive => panic!("invalid memory ordering"), } } @@ -1443,9 +1462,10 @@ pub fn fence(order: Ordering) { match order { Acquire => intrinsics::atomic_fence_acq(), Release => intrinsics::atomic_fence_rel(), - AcqRel => intrinsics::atomic_fence_acqrel(), - SeqCst => intrinsics::atomic_fence(), - Relaxed => panic!("there is no such thing as a relaxed fence") + AcqRel => intrinsics::atomic_fence_acqrel(), + SeqCst => intrinsics::atomic_fence(), + Relaxed => panic!("there is no such thing as a relaxed fence"), + __Nonexhaustive => panic!("invalid memory ordering"), } } } diff --git a/src/libcoretest/char.rs b/src/libcoretest/char.rs index 199437a431..7da0b6902f 100644 --- a/src/libcoretest/char.rs +++ b/src/libcoretest/char.rs @@ -8,7 +8,7 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -use std::char; +use std::{char,str}; use std::convert::TryFrom; #[test] @@ -248,10 +248,12 @@ fn test_escape_unicode() { #[test] fn test_encode_utf8() { fn check(input: char, expect: &[u8]) { - assert_eq!(input.encode_utf8().as_slice(), expect); - for (a, b) in input.encode_utf8().zip(expect) { - assert_eq!(a, *b); - } + let mut buf = [0; 4]; + let ptr = buf.as_ptr(); + let s = input.encode_utf8(&mut buf); + assert_eq!(s.as_ptr() as usize, ptr as usize); + assert!(str::from_utf8(s.as_bytes()).is_ok()); + assert_eq!(s.as_bytes(), expect); } check('x', &[0x78]); @@ -263,10 +265,11 @@ fn test_encode_utf8() { #[test] fn test_encode_utf16() { fn check(input: char, expect: &[u16]) { - assert_eq!(input.encode_utf16().as_slice(), expect); - for (a, b) in input.encode_utf16().zip(expect) { - assert_eq!(a, *b); - } + let mut buf = [0; 2]; + let ptr = buf.as_mut_ptr(); + let b = input.encode_utf16(&mut buf); + assert_eq!(b.as_mut_ptr() as usize, ptr as usize); + assert_eq!(b, expect); } check('x', &[0x0078]); diff --git a/src/libcoretest/cmp.rs b/src/libcoretest/cmp.rs index 051356cad1..e3c65ad8b3 100644 --- a/src/libcoretest/cmp.rs +++ b/src/libcoretest/cmp.rs @@ -41,6 +41,32 @@ fn test_ordering_order() { assert_eq!(Greater.cmp(&Less), Greater); } +#[test] +fn test_ordering_then() { + assert_eq!(Equal.then(Less), Less); + assert_eq!(Equal.then(Equal), Equal); + assert_eq!(Equal.then(Greater), Greater); + assert_eq!(Less.then(Less), Less); + assert_eq!(Less.then(Equal), Less); + assert_eq!(Less.then(Greater), Less); + assert_eq!(Greater.then(Less), Greater); + assert_eq!(Greater.then(Equal), Greater); + assert_eq!(Greater.then(Greater), Greater); +} + +#[test] +fn test_ordering_then_with() { + assert_eq!(Equal.then_with(|| Less), Less); + assert_eq!(Equal.then_with(|| Equal), Equal); + assert_eq!(Equal.then_with(|| Greater), Greater); + assert_eq!(Less.then_with(|| Less), Less); + assert_eq!(Less.then_with(|| Equal), Less); + assert_eq!(Less.then_with(|| Greater), Less); + assert_eq!(Greater.then_with(|| Less), Greater); + assert_eq!(Greater.then_with(|| Equal), Greater); + assert_eq!(Greater.then_with(|| Greater), Greater); +} + #[test] fn test_user_defined_eq() { // Our type. diff --git a/src/libcoretest/hash/sip.rs b/src/libcoretest/hash/sip.rs index b465d7de18..fa3bfdea42 100644 --- a/src/libcoretest/hash/sip.rs +++ b/src/libcoretest/hash/sip.rs @@ -14,6 +14,7 @@ use test::{Bencher, black_box}; use core::hash::{Hash, Hasher}; use core::hash::{SipHasher, SipHasher13, SipHasher24}; +use core::{slice, mem}; // Hash just the bytes of the slice, without length prefix struct Bytes<'a>(&'a [u8]); @@ -327,6 +328,26 @@ fn test_hash_no_concat_alias() { assert!(hash(&v) != hash(&w)); } +#[test] +fn test_write_short_works() { + let test_usize = 0xd0c0b0a0usize; + let mut h1 = SipHasher24::new(); + h1.write_usize(test_usize); + h1.write(b"bytes"); + h1.write(b"string"); + h1.write_u8(0xFFu8); + h1.write_u8(0x01u8); + let mut h2 = SipHasher24::new(); + h2.write(unsafe { + slice::from_raw_parts(&test_usize as *const _ as *const u8, + mem::size_of::()) + }); + h2.write(b"bytes"); + h2.write(b"string"); + h2.write(&[0xFFu8, 0x01u8]); + assert_eq!(h1.finish(), h2.finish()); +} + #[bench] fn bench_str_under_8_bytes(b: &mut Bencher) { let s = "foo"; diff --git a/src/libcoretest/iter.rs b/src/libcoretest/iter.rs index 27eb25537f..58b6444ef8 100644 --- a/src/libcoretest/iter.rs +++ b/src/libcoretest/iter.rs @@ -985,6 +985,18 @@ fn test_empty() { assert_eq!(it.next(), None); } +#[test] +fn test_chain_fold() { + let xs = [1, 2, 3]; + let ys = [1, 2, 0]; + + let mut iter = xs.iter().chain(&ys); + iter.next(); + let mut result = Vec::new(); + iter.fold((), |(), &elt| result.push(elt)); + assert_eq!(&[2, 3, 1, 2, 0], &result[..]); +} + #[bench] fn bench_rposition(b: &mut Bencher) { let it: Vec = (0..300).collect(); diff --git a/src/libcoretest/lib.rs b/src/libcoretest/lib.rs index 590bf478aa..b8c01e570f 100644 --- a/src/libcoretest/lib.rs +++ b/src/libcoretest/lib.rs @@ -34,6 +34,8 @@ #![feature(unique)] #![feature(iter_max_by)] #![feature(iter_min_by)] +#![feature(ordering_chaining)] +#![feature(result_unwrap_or_default)] extern crate core; extern crate test; diff --git a/src/libcoretest/num/flt2dec/estimator.rs b/src/libcoretest/num/flt2dec/estimator.rs index 857aae72c8..0bca616ea9 100644 --- a/src/libcoretest/num/flt2dec/estimator.rs +++ b/src/libcoretest/num/flt2dec/estimator.rs @@ -8,6 +8,11 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. +// FIXME https://github.com/kripken/emscripten/issues/4563 +// NB we have to actually not compile this test to avoid +// an undefined symbol error +#![cfg(not(target_os = "emscripten"))] + use core::num::flt2dec::estimator::*; #[test] diff --git a/src/libcoretest/result.rs b/src/libcoretest/result.rs index 6e9f653dcd..bc2cd8bbfc 100644 --- a/src/libcoretest/result.rs +++ b/src/libcoretest/result.rs @@ -183,3 +183,9 @@ pub fn test_iter_mut() { } assert_eq!(err, Err("error")); } + +#[test] +pub fn test_unwrap_or_default() { + assert_eq!(op1().unwrap_or_default(), 666); + assert_eq!(op2().unwrap_or_default(), 0); +} diff --git a/src/libflate/lib.rs b/src/libflate/lib.rs index 63913f2878..3c608ef9c9 100644 --- a/src/libflate/lib.rs +++ b/src/libflate/lib.rs @@ -94,11 +94,14 @@ extern "C" { -> *mut c_void; } -const LZ_NORM: c_int = 0x80; // LZ with 128 probes, "normal" -const TINFL_FLAG_PARSE_ZLIB_HEADER: c_int = 0x1; // parse zlib header and adler32 checksum -const TDEFL_WRITE_ZLIB_HEADER: c_int = 0x01000; // write zlib header and adler32 checksum +const LZ_FAST: c_int = 0x01; // LZ with 1 probe, "fast" +const TDEFL_GREEDY_PARSING_FLAG: c_int = 0x04000; // fast greedy parsing instead of lazy parsing -fn deflate_bytes_internal(bytes: &[u8], flags: c_int) -> Bytes { +/// Compress a buffer without writing any sort of header on the output. Fast +/// compression is used because it is almost twice as fast as default +/// compression and the compression ratio is only marginally worse. +pub fn deflate_bytes(bytes: &[u8]) -> Bytes { + let flags = LZ_FAST | TDEFL_GREEDY_PARSING_FLAG; unsafe { let mut outsz: size_t = 0; let res = tdefl_compress_mem_to_heap(bytes.as_ptr() as *const _, @@ -113,17 +116,9 @@ fn deflate_bytes_internal(bytes: &[u8], flags: c_int) -> Bytes { } } -/// Compress a buffer, without writing any sort of header on the output. -pub fn deflate_bytes(bytes: &[u8]) -> Bytes { - deflate_bytes_internal(bytes, LZ_NORM) -} - -/// Compress a buffer, using a header that zlib can understand. -pub fn deflate_bytes_zlib(bytes: &[u8]) -> Bytes { - deflate_bytes_internal(bytes, LZ_NORM | TDEFL_WRITE_ZLIB_HEADER) -} - -fn inflate_bytes_internal(bytes: &[u8], flags: c_int) -> Result { +/// Decompress a buffer without parsing any sort of header on the input. +pub fn inflate_bytes(bytes: &[u8]) -> Result { + let flags = 0; unsafe { let mut outsz: size_t = 0; let res = tinfl_decompress_mem_to_heap(bytes.as_ptr() as *const _, @@ -141,16 +136,6 @@ fn inflate_bytes_internal(bytes: &[u8], flags: c_int) -> Result { } } -/// Decompress a buffer, without parsing any sort of header on the input. -pub fn inflate_bytes(bytes: &[u8]) -> Result { - inflate_bytes_internal(bytes, 0) -} - -/// Decompress a buffer that starts with a zlib header. -pub fn inflate_bytes_zlib(bytes: &[u8]) -> Result { - inflate_bytes_internal(bytes, TINFL_FLAG_PARSE_ZLIB_HEADER) -} - #[cfg(test)] mod tests { #![allow(deprecated)] diff --git a/src/libgetopts/lib.rs b/src/libgetopts/lib.rs index 42200795bb..4d2f1b999a 100644 --- a/src/libgetopts/lib.rs +++ b/src/libgetopts/lib.rs @@ -1610,8 +1610,8 @@ Options: #[test] fn test_args_with_equals() { - let args = vec!("--one".to_string(), "A=B".to_string(), - "--two=C=D".to_string()); + let args = vec!["--one".to_string(), "A=B".to_string(), + "--two=C=D".to_string()]; let opts = vec![optopt("o", "one", "One", "INFO"), optopt("t", "two", "Two", "INFO")]; let matches = &match getopts(&args, &opts) { diff --git a/src/libgraphviz/lib.rs b/src/libgraphviz/lib.rs index 95c46ec571..03057af4a8 100644 --- a/src/libgraphviz/lib.rs +++ b/src/libgraphviz/lib.rs @@ -58,7 +58,7 @@ //! struct Edges(Vec); //! //! pub fn render_to(output: &mut W) { -//! let edges = Edges(vec!((0,1), (0,2), (1,3), (2,3), (3,4), (4,4))); +//! let edges = Edges(vec![(0,1), (0,2), (1,3), (2,3), (3,4), (4,4)]); //! dot::render(&edges, output).unwrap() //! } //! @@ -164,8 +164,8 @@ //! struct Graph { nodes: Vec<&'static str>, edges: Vec<(usize,usize)> } //! //! pub fn render_to(output: &mut W) { -//! let nodes = vec!("{x,y}","{x}","{y}","{}"); -//! let edges = vec!((0,1), (0,2), (1,3), (2,3)); +//! let nodes = vec!["{x,y}","{x}","{y}","{}"]; +//! let edges = vec![(0,1), (0,2), (1,3), (2,3)]; //! let graph = Graph { nodes: nodes, edges: edges }; //! //! dot::render(&graph, output).unwrap() @@ -226,8 +226,8 @@ //! struct Graph { nodes: Vec<&'static str>, edges: Vec<(usize,usize)> } //! //! pub fn render_to(output: &mut W) { -//! let nodes = vec!("{x,y}","{x}","{y}","{}"); -//! let edges = vec!((0,1), (0,2), (1,3), (2,3)); +//! let nodes = vec!["{x,y}","{x}","{y}","{}"]; +//! let edges = vec![(0,1), (0,2), (1,3), (2,3)]; //! let graph = Graph { nodes: nodes, edges: edges }; //! //! dot::render(&graph, output).unwrap() diff --git a/src/liblibc/.travis.yml b/src/liblibc/.travis.yml index e02f9ca256..1b05af7bc6 100644 --- a/src/liblibc/.travis.yml +++ b/src/liblibc/.travis.yml @@ -33,7 +33,7 @@ matrix: # build documentation - os: linux env: TARGET=x86_64-unknown-linux-gnu - rust: nightly + rust: stable script: sh ci/dox.sh # stable compat @@ -78,13 +78,16 @@ matrix: rust: stable - os: linux env: TARGET=powerpc64-unknown-linux-gnu - rust: stable + rust: beta - os: linux env: TARGET=mips-unknown-linux-musl rust: stable - os: linux env: TARGET=mipsel-unknown-linux-musl rust: stable + - os: linux + env: TARGET=mips64-unknown-linux-gnuabi64 + rust: nightly # beta - os: linux diff --git a/src/liblibc/Cargo.lock b/src/liblibc/Cargo.lock index 6313e804e9..5332bf28bf 100644 --- a/src/liblibc/Cargo.lock +++ b/src/liblibc/Cargo.lock @@ -2,8 +2,8 @@ name = "libc-test" version = "0.1.0" dependencies = [ - "ctest 0.1.0 (git+https://github.com/alexcrichton/ctest)", - "libc 0.2.16", + "ctest 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.17", ] [[package]] @@ -14,7 +14,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] name = "ctest" version = "0.1.0" -source = "git+https://github.com/alexcrichton/ctest#2839e49847a6adca6e96cc81c46a1f03f8562ac0" +source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "gcc 0.3.35 (registry+https://github.com/rust-lang/crates.io-index)", "syntex_syntax 0.19.1 (registry+https://github.com/rust-lang/crates.io-index)", @@ -29,7 +29,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" name = "generate-files" version = "0.1.0" dependencies = [ - "ctest 0.1.0 (git+https://github.com/alexcrichton/ctest)", + "ctest 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -48,7 +48,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] name = "libc" -version = "0.2.16" +version = "0.2.17" [[package]] name = "log" @@ -99,7 +99,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" [metadata] "checksum bitflags 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)" = "32866f4d103c4e438b1db1158aa1b1a80ee078e5d77a59a2f906fd62a577389c" -"checksum ctest 0.1.0 (git+https://github.com/alexcrichton/ctest)" = "" +"checksum ctest 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "0d8e8e44b9fb51a835b9193863b4b873dea29756cf4ba5151c0a6cc0f15fbdeb" "checksum gcc 0.3.35 (registry+https://github.com/rust-lang/crates.io-index)" = "91ecd03771effb0c968fd6950b37e89476a578aaf1c70297d8e92b6516ec3312" "checksum kernel32-sys 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "7507624b29483431c0ba2d82aece8ca6cdba9382bff4ddd0f7490560c056098d" "checksum libc 0.1.12 (registry+https://github.com/rust-lang/crates.io-index)" = "e32a70cf75e5846d53a673923498228bbec6a8624708a9ea5645f075d6276122" diff --git a/src/liblibc/Cargo.toml b/src/liblibc/Cargo.toml index 5dc0ec4e4e..c08ab3aab9 100644 --- a/src/liblibc/Cargo.toml +++ b/src/liblibc/Cargo.toml @@ -1,7 +1,7 @@ [package] name = "libc" -version = "0.2.16" +version = "0.2.17" authors = ["The Rust Project Developers"] license = "MIT/Apache-2.0" readme = "README.md" diff --git a/src/liblibc/ci/docker/mips64-unknown-linux-gnuabi64/Dockerfile b/src/liblibc/ci/docker/mips64-unknown-linux-gnuabi64/Dockerfile new file mode 100644 index 0000000000..2eb5de2453 --- /dev/null +++ b/src/liblibc/ci/docker/mips64-unknown-linux-gnuabi64/Dockerfile @@ -0,0 +1,11 @@ +FROM ubuntu:16.10 + +RUN apt-get update +RUN apt-get install -y --no-install-recommends \ + gcc libc6-dev qemu-user ca-certificates \ + gcc-mips64-linux-gnuabi64 libc6-dev-mips64-cross \ + qemu-system-mips64 + +ENV CARGO_TARGET_MIPS64_UNKNOWN_LINUX_GNUABI64_LINKER=mips64-linux-gnuabi64-gcc \ + CC_mips64_unknown_linux_gnuabi64=mips64-linux-gnuabi64-gcc \ + PATH=$PATH:/rust/bin diff --git a/src/liblibc/ci/run.sh b/src/liblibc/ci/run.sh index 760353bf57..15721ab965 100755 --- a/src/liblibc/ci/run.sh +++ b/src/liblibc/ci/run.sh @@ -121,6 +121,10 @@ case "$TARGET" in qemu-mips -L /usr/mips-linux-gnu $CARGO_TARGET_DIR/$TARGET/debug/libc-test ;; + mips64-unknown-linux-gnuabi64) + qemu-mips64 -L /usr/mips64-linux-gnuabi64 $CARGO_TARGET_DIR/$TARGET/debug/libc-test + ;; + mips-unknown-linux-musl) qemu-mips -L /toolchain/staging_dir/toolchain-mips_34kc_gcc-5.3.0_musl-1.1.15 \ $CARGO_TARGET_DIR/$TARGET/debug/libc-test diff --git a/src/liblibc/libc-test/Cargo.toml b/src/liblibc/libc-test/Cargo.toml index dfcf127c48..4e7c88450e 100644 --- a/src/liblibc/libc-test/Cargo.toml +++ b/src/liblibc/libc-test/Cargo.toml @@ -8,7 +8,4 @@ build = "build.rs" libc = { path = ".." } [build-dependencies] -ctest = { git = "https://github.com/alexcrichton/ctest" } - -[replace] -"gcc:0.3.35" = { git = "https://github.com/alexcrichton/gcc-rs" } +ctest = "0.1" diff --git a/src/liblibc/libc-test/generate-files/Cargo.toml b/src/liblibc/libc-test/generate-files/Cargo.toml index 9615a63d49..8c19856276 100644 --- a/src/liblibc/libc-test/generate-files/Cargo.toml +++ b/src/liblibc/libc-test/generate-files/Cargo.toml @@ -13,4 +13,4 @@ name = "generate-files" path = "../build.rs" [dependencies] -ctest = { git = "https://github.com/alexcrichton/ctest" } +ctest = "0.1" diff --git a/src/liblibc/src/lib.rs b/src/liblibc/src/lib.rs index c25daa5de0..dcc4791f9a 100644 --- a/src/liblibc/src/lib.rs +++ b/src/liblibc/src/lib.rs @@ -33,9 +33,6 @@ #![cfg_attr(all(target_os = "linux", target_arch = "aarch64"), doc( html_root_url = "https://doc.rust-lang.org/libc/aarch64-unknown-linux-gnu" ))] -#![cfg_attr(all(target_os = "linux", target_arch = "s390x"), doc( - html_root_url = "https://doc.rust-lang.org/libc/s390x-unknown-linux-gnu" -))] #![cfg_attr(all(target_os = "linux", target_env = "musl"), doc( html_root_url = "https://doc.rust-lang.org/libc/x86_64-unknown-linux-musl" ))] diff --git a/src/liblibc/src/unix/mod.rs b/src/liblibc/src/unix/mod.rs index e822b063d9..3e03eea675 100644 --- a/src/liblibc/src/unix/mod.rs +++ b/src/liblibc/src/unix/mod.rs @@ -228,6 +228,10 @@ cfg_if! { #[link(name = "root")] #[link(name = "network")] extern {} + } else if #[cfg(target_os = "fuchsia")] { + #[link(name = "c")] + #[link(name = "mxio")] + extern {} } else { #[link(name = "c")] #[link(name = "m")] @@ -833,12 +837,18 @@ extern { #[cfg_attr(all(target_os = "macos", target_arch = "x86"), link_name = "nice$UNIX2003")] pub fn nice(incr: ::c_int) -> ::c_int; + + pub fn grantpt(fd: ::c_int) -> ::c_int; + pub fn posix_openpt(flags: ::c_int) -> ::c_int; + pub fn ptsname(fd: ::c_int) -> *mut ::c_char; + pub fn unlockpt(fd: ::c_int) -> ::c_int; } cfg_if! { if #[cfg(any(target_os = "linux", target_os = "android", - target_os = "emscripten"))] { + target_os = "emscripten", + target_os = "fuchsia"))] { mod notbsd; pub use self::notbsd::*; } else if #[cfg(any(target_os = "macos", diff --git a/src/liblibc/src/unix/notbsd/linux/mips64.rs b/src/liblibc/src/unix/notbsd/linux/mips64.rs index 9612495314..30c336e690 100644 --- a/src/liblibc/src/unix/notbsd/linux/mips64.rs +++ b/src/liblibc/src/unix/notbsd/linux/mips64.rs @@ -213,10 +213,12 @@ pub const O_NONBLOCK: ::c_int = 128; pub const POSIX_FADV_DONTNEED: ::c_int = 4; pub const POSIX_FADV_NOREUSE: ::c_int = 5; pub const PTHREAD_STACK_MIN: ::size_t = 131072; +pub const NFS_SUPER_MAGIC: ::c_long = 0x00006969; pub const RLIM_INFINITY: ::rlim_t = 0xffffffffffffffff; pub const SA_ONSTACK: ::c_int = 0x08000000; pub const SA_SIGINFO: ::c_int = 0x00000008; pub const SIGBUS: ::c_int = 10; +pub const SIGSYS: ::c_int = 12; pub const SIGSTKSZ: ::size_t = 0x2000; pub const SIG_SETMASK: ::c_int = 3; pub const SOCK_DGRAM: ::c_int = 1; @@ -227,6 +229,10 @@ pub const SO_ERROR: ::c_int = 4103; pub const SO_RCVTIMEO: ::c_int = 4102; pub const SO_REUSEADDR: ::c_int = 4; pub const SO_SNDTIMEO: ::c_int = 4101; +pub const SO_REUSEPORT: ::c_int = 0x200; +pub const SO_SNDBUF: ::c_int = 4097; +pub const SO_RCVBUF: ::c_int = 4098; +pub const SO_KEEPALIVE: ::c_int = 8; #[link(name = "util")] extern { diff --git a/src/liblibc/src/unix/notbsd/linux/mod.rs b/src/liblibc/src/unix/notbsd/linux/mod.rs index ea820ea5c6..c011b8c48e 100644 --- a/src/liblibc/src/unix/notbsd/linux/mod.rs +++ b/src/liblibc/src/unix/notbsd/linux/mod.rs @@ -714,6 +714,8 @@ extern { riovcnt: ::c_ulong, flags: ::c_ulong) -> isize; pub fn reboot(how_to: ::c_int) -> ::c_int; + pub fn setresgid(rgid: ::gid_t, egid: ::gid_t, sgid: ::gid_t) -> ::c_int; + pub fn setresuid(ruid: ::uid_t, euid: ::uid_t, suid: ::uid_t) -> ::c_int; // Not available now on Android pub fn mkfifoat(dirfd: ::c_int, pathname: *const ::c_char, @@ -728,6 +730,7 @@ extern { cfg_if! { if #[cfg(any(target_env = "musl", + target_os = "fuchsia", target_os = "emscripten"))] { mod musl; pub use self::musl::*; diff --git a/src/liblibc/src/unix/notbsd/linux/musl/mod.rs b/src/liblibc/src/unix/notbsd/linux/musl/mod.rs index 69a85b86ea..1808e44359 100644 --- a/src/liblibc/src/unix/notbsd/linux/musl/mod.rs +++ b/src/liblibc/src/unix/notbsd/linux/musl/mod.rs @@ -231,7 +231,7 @@ extern { } cfg_if! { - if #[cfg(any(target_arch = "x86_64"))] { + if #[cfg(any(target_arch = "x86_64", target_arch = "aarch64"))] { mod b64; pub use self::b64::*; } else if #[cfg(any(target_arch = "x86", diff --git a/src/liblibc/src/unix/notbsd/linux/other/mod.rs b/src/liblibc/src/unix/notbsd/linux/other/mod.rs index b100cec54b..97c28ea81c 100644 --- a/src/liblibc/src/unix/notbsd/linux/other/mod.rs +++ b/src/liblibc/src/unix/notbsd/linux/other/mod.rs @@ -563,6 +563,7 @@ extern { pub fn pututxline(ut: *const utmpx) -> *mut utmpx; pub fn setutxent(); pub fn endutxent(); + pub fn getpt() -> ::c_int; } #[link(name = "util")] diff --git a/src/liblibc/src/unix/notbsd/mod.rs b/src/liblibc/src/unix/notbsd/mod.rs index a53211a2b8..d11202b7b7 100644 --- a/src/liblibc/src/unix/notbsd/mod.rs +++ b/src/liblibc/src/unix/notbsd/mod.rs @@ -53,7 +53,9 @@ s! { pub ai_protocol: ::c_int, pub ai_addrlen: socklen_t, - #[cfg(any(target_os = "linux", target_os = "emscripten"))] + #[cfg(any(target_os = "linux", + target_os = "emscripten", + target_os = "fuchsia"))] pub ai_addr: *mut ::sockaddr, pub ai_canonname: *mut c_char, @@ -851,11 +853,15 @@ extern { flg: ::c_int) -> ::c_int; pub fn pthread_mutex_timedlock(lock: *mut pthread_mutex_t, abstime: *const ::timespec) -> ::c_int; + pub fn ptsname_r(fd: ::c_int, + buf: *mut ::c_char, + buflen: ::size_t) -> ::c_int; } cfg_if! { if #[cfg(any(target_os = "linux", - target_os = "emscripten"))] { + target_os = "emscripten", + target_os = "fuchsia"))] { mod linux; pub use self::linux::*; } else if #[cfg(target_os = "android")] { diff --git a/src/liblog/directive.rs b/src/liblog/directive.rs index f1ebf16737..eb50d6e613 100644 --- a/src/liblog/directive.rs +++ b/src/liblog/directive.rs @@ -22,12 +22,12 @@ pub const LOG_LEVEL_NAMES: [&'static str; 5] = ["ERROR", "WARN", "INFO", "DEBUG" /// Parse an individual log level that is either a number or a symbolic log level fn parse_log_level(level: &str) -> Option { level.parse::() - .ok() - .or_else(|| { - let pos = LOG_LEVEL_NAMES.iter().position(|&name| name.eq_ignore_ascii_case(level)); - pos.map(|p| p as u32 + 1) - }) - .map(|p| cmp::min(p, ::MAX_LOG_LEVEL)) + .ok() + .or_else(|| { + let pos = LOG_LEVEL_NAMES.iter().position(|&name| name.eq_ignore_ascii_case(level)); + pos.map(|p| p as u32 + 1) + }) + .map(|p| cmp::min(p, ::MAX_LOG_LEVEL)) } /// Parse a logging specification string (e.g: "crate1,crate2::mod3,crate3::x=1/foo") @@ -52,32 +52,31 @@ pub fn parse_logging_spec(spec: &str) -> (Vec, Option) { 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) => { - // if the single argument is a log-level string or number, - // treat that as a global fallback - match parse_log_level(part0) { - Some(num) => (num, None), - None => (::MAX_LOG_LEVEL, Some(part0)), + let (log_level, name) = + match (parts.next(), parts.next().map(|s| s.trim()), parts.next()) { + (Some(part0), None, None) => { + // if the single argument is a log-level string or number, + // treat that as a global fallback + match parse_log_level(part0) { + Some(num) => (num, None), + None => (::MAX_LOG_LEVEL, Some(part0)), + } } - } - (Some(part0), Some(""), None) => (::MAX_LOG_LEVEL, Some(part0)), - (Some(part0), Some(part1), None) => { - match parse_log_level(part1) { - Some(num) => (num, Some(part0)), - _ => { - println!("warning: invalid logging spec '{}', ignoring it", part1); - continue; + (Some(part0), Some(""), None) => (::MAX_LOG_LEVEL, Some(part0)), + (Some(part0), Some(part1), None) => { + match parse_log_level(part1) { + Some(num) => (num, Some(part0)), + _ => { + println!("warning: invalid logging spec '{}', ignoring it", part1); + continue; + } } } - } - _ => { - println!("warning: invalid logging spec '{}', ignoring it", s); - continue; - } - }; + _ => { + println!("warning: invalid logging spec '{}', ignoring it", s); + continue; + } + }; dirs.push(LogDirective { name: name.map(str::to_owned), level: log_level, diff --git a/src/libpanic_unwind/Cargo.lock b/src/libpanic_unwind/Cargo.lock deleted file mode 100644 index 20d826d4a4..0000000000 --- a/src/libpanic_unwind/Cargo.lock +++ /dev/null @@ -1,27 +0,0 @@ -[root] -name = "panic_unwind" -version = "0.0.0" -dependencies = [ - "alloc 0.0.0", - "core 0.0.0", - "libc 0.0.0", -] - -[[package]] -name = "alloc" -version = "0.0.0" -dependencies = [ - "core 0.0.0", -] - -[[package]] -name = "core" -version = "0.0.0" - -[[package]] -name = "libc" -version = "0.0.0" -dependencies = [ - "core 0.0.0", -] - diff --git a/src/libpanic_unwind/dwarf/eh.rs b/src/libpanic_unwind/dwarf/eh.rs index 2284a9bbb7..e7994f4e0e 100644 --- a/src/libpanic_unwind/dwarf/eh.rs +++ b/src/libpanic_unwind/dwarf/eh.rs @@ -116,7 +116,7 @@ pub unsafe fn find_eh_action(lsda: *const u8, context: &EHContext) -> EHAction { // The "IP" is an index into the call-site table, with two exceptions: // -1 means 'no-action', and 0 means 'terminate'. match ip as isize { - -1 => return EHAction::None, + -1 => return EHAction::None, 0 => return EHAction::Terminate, _ => (), } @@ -182,12 +182,8 @@ unsafe fn read_encoded_pointer(reader: &mut DwarfReader, assert!(context.func_start != 0); context.func_start } - DW_EH_PE_textrel => { - (*context.get_text_start)() - } - DW_EH_PE_datarel => { - (*context.get_data_start)() - } + DW_EH_PE_textrel => (*context.get_text_start)(), + DW_EH_PE_datarel => (*context.get_data_start)(), _ => panic!(), }; diff --git a/src/libpanic_unwind/emcc.rs b/src/libpanic_unwind/emcc.rs new file mode 100644 index 0000000000..0e48e37c92 --- /dev/null +++ b/src/libpanic_unwind/emcc.rs @@ -0,0 +1,75 @@ +// Copyright 2016 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +//! Unwinding for emscripten +//! +//! Whereas Rust's usual unwinding implementation for Unix platforms +//! calls into the libunwind APIs directly, on emscripten we instead +//! call into the C++ unwinding APIs. This is just an expedience since +//! emscripten's runtime always implements those APIs and does not +//! implement libunwind. + +#![allow(private_no_mangle_fns)] + +use core::any::Any; +use core::ptr; +use alloc::boxed::Box; +use libc::{self, c_int}; +use unwind as uw; +use core::mem; + +pub fn payload() -> *mut u8 { + ptr::null_mut() +} + +pub unsafe fn cleanup(ptr: *mut u8) -> Box { + assert!(!ptr.is_null()); + let ex = ptr::read(ptr as *mut _); + __cxa_free_exception(ptr as *mut _); + ex +} + +pub unsafe fn panic(data: Box) -> u32 { + let sz = mem::size_of_val(&data); + let exception = __cxa_allocate_exception(sz); + if exception == ptr::null_mut() { + return uw::_URC_FATAL_PHASE1_ERROR as u32; + } + let exception = exception as *mut Box; + ptr::write(exception, data); + __cxa_throw(exception as *mut _, ptr::null_mut(), ptr::null_mut()); + + unreachable!() +} + +#[lang = "eh_personality"] +#[no_mangle] +unsafe extern "C" fn rust_eh_personality(version: c_int, + actions: uw::_Unwind_Action, + exception_class: uw::_Unwind_Exception_Class, + exception_object: *mut uw::_Unwind_Exception, + context: *mut uw::_Unwind_Context) + -> uw::_Unwind_Reason_Code { + __gxx_personality_v0(version, actions, exception_class, exception_object, context) +} + +extern "C" { + fn __cxa_allocate_exception(thrown_size: libc::size_t) -> *mut libc::c_void; + fn __cxa_free_exception(thrown_exception: *mut libc::c_void); + fn __cxa_throw(thrown_exception: *mut libc::c_void, + tinfo: *mut libc::c_void, + dest: *mut libc::c_void); + fn __gxx_personality_v0(version: c_int, + actions: uw::_Unwind_Action, + exception_class: uw::_Unwind_Exception_Class, + exception_object: *mut uw::_Unwind_Exception, + context: *mut uw::_Unwind_Context) + -> uw::_Unwind_Reason_Code; +} diff --git a/src/libpanic_unwind/gcc.rs b/src/libpanic_unwind/gcc.rs index 33b24fbaa2..73264fab69 100644 --- a/src/libpanic_unwind/gcc.rs +++ b/src/libpanic_unwind/gcc.rs @@ -124,7 +124,7 @@ const UNWIND_DATA_REG: (i32, i32) = (0, 1); // RAX, RDX #[cfg(any(target_arch = "arm", target_arch = "aarch64"))] const UNWIND_DATA_REG: (i32, i32) = (0, 1); // R0, R1 / X0, X1 -#[cfg(any(target_arch = "mips", target_arch = "mipsel", target_arch = "mips64"))] +#[cfg(any(target_arch = "mips", target_arch = "mips64"))] const UNWIND_DATA_REG: (i32, i32) = (4, 5); // A0, A1 #[cfg(any(target_arch = "powerpc", target_arch = "powerpc64"))] @@ -156,14 +156,16 @@ unsafe extern "C" fn rust_eh_personality(version: c_int, let eh_action = find_eh_action(context); if actions as i32 & uw::_UA_SEARCH_PHASE as i32 != 0 { match eh_action { - EHAction::None | EHAction::Cleanup(_) => return uw::_URC_CONTINUE_UNWIND, + EHAction::None | + EHAction::Cleanup(_) => return uw::_URC_CONTINUE_UNWIND, EHAction::Catch(_) => return uw::_URC_HANDLER_FOUND, EHAction::Terminate => return uw::_URC_FATAL_PHASE1_ERROR, } } else { match eh_action { EHAction::None => return uw::_URC_CONTINUE_UNWIND, - EHAction::Cleanup(lpad) | EHAction::Catch(lpad) => { + EHAction::Cleanup(lpad) | + EHAction::Catch(lpad) => { uw::_Unwind_SetGR(context, UNWIND_DATA_REG.0, exception_object as uintptr_t); uw::_Unwind_SetGR(context, UNWIND_DATA_REG.1, 0); uw::_Unwind_SetIP(context, lpad); @@ -182,7 +184,7 @@ unsafe extern "C" fn rust_eh_personality(version: c_int, unsafe extern "C" fn rust_eh_personality(state: uw::_Unwind_State, exception_object: *mut uw::_Unwind_Exception, context: *mut uw::_Unwind_Context) - -> uw::_Unwind_Reason_Code { + -> uw::_Unwind_Reason_Code { let state = state as c_int; let action = state & uw::_US_ACTION_MASK as c_int; let search_phase = if action == uw::_US_VIRTUAL_UNWIND_FRAME as c_int { @@ -191,7 +193,7 @@ unsafe extern "C" fn rust_eh_personality(state: uw::_Unwind_State, // we want to continue unwinding the stack, otherwise all our backtraces // would end at __rust_try if state & uw::_US_FORCE_UNWIND as c_int != 0 { - return continue_unwind(exception_object, context) + return continue_unwind(exception_object, context); } true } else if action == uw::_US_UNWIND_FRAME_STARTING as c_int { @@ -207,7 +209,9 @@ unsafe extern "C" fn rust_eh_personality(state: uw::_Unwind_State, // To preserve signatures of functions like _Unwind_GetLanguageSpecificData(), which // take only the context pointer, GCC personality routines stash a pointer to exception_object // in the context, using location reserved for ARM's "scratch register" (r12). - uw::_Unwind_SetGR(context, uw::UNWIND_POINTER_REG, exception_object as uw::_Unwind_Ptr); + uw::_Unwind_SetGR(context, + uw::UNWIND_POINTER_REG, + exception_object as uw::_Unwind_Ptr); // ...A more principled approach would be to provide the full definition of ARM's // _Unwind_Context in our libunwind bindings and fetch the required data from there directly, // bypassing DWARF compatibility functions. @@ -223,7 +227,8 @@ unsafe extern "C" fn rust_eh_personality(state: uw::_Unwind_State, } else { match eh_action { EHAction::None => return continue_unwind(exception_object, context), - EHAction::Cleanup(lpad) | EHAction::Catch(lpad) => { + EHAction::Cleanup(lpad) | + EHAction::Catch(lpad) => { uw::_Unwind_SetGR(context, UNWIND_DATA_REG.0, exception_object as uintptr_t); uw::_Unwind_SetGR(context, UNWIND_DATA_REG.1, 0); uw::_Unwind_SetIP(context, lpad); @@ -247,8 +252,8 @@ unsafe extern "C" fn rust_eh_personality(state: uw::_Unwind_State, // defined in libgcc extern "C" { fn __gnu_unwind_frame(exception_object: *mut uw::_Unwind_Exception, - context: *mut uw::_Unwind_Context) - -> uw::_Unwind_Reason_Code; + context: *mut uw::_Unwind_Context) + -> uw::_Unwind_Reason_Code; } } @@ -287,7 +292,7 @@ unsafe extern "C" fn rust_eh_unwind_resume(panic_ctx: *mut u8) -> ! { // to actively register their unwind info sections via unwinder API. // // This module defines two symbols which are referenced and called from -// rsbegin.rs to reigster our information with the GCC runtime. The +// rsbegin.rs to register our information with the GCC runtime. The // implementation of stack unwinding is (for now) deferred to libgcc_eh, however // Rust crates use these Rust-specific entry points to avoid potential clashes // with any GCC runtime. diff --git a/src/libpanic_unwind/lib.rs b/src/libpanic_unwind/lib.rs index 11dd9befe0..ff483fa823 100644 --- a/src/libpanic_unwind/lib.rs +++ b/src/libpanic_unwind/lib.rs @@ -68,10 +68,16 @@ mod imp; mod imp; // i686-pc-windows-gnu and all others -#[cfg(any(unix, all(windows, target_arch = "x86", target_env = "gnu")))] +#[cfg(any(all(unix, not(target_os = "emscripten")), + all(windows, target_arch = "x86", target_env = "gnu")))] #[path = "gcc.rs"] mod imp; +// emscripten +#[cfg(target_os = "emscripten")] +#[path = "emcc.rs"] +mod imp; + mod dwarf; mod windows; diff --git a/src/libpanic_unwind/seh64_gnu.rs b/src/libpanic_unwind/seh64_gnu.rs index e6d3920b29..d4906b556b 100644 --- a/src/libpanic_unwind/seh64_gnu.rs +++ b/src/libpanic_unwind/seh64_gnu.rs @@ -129,7 +129,8 @@ unsafe fn find_landing_pad(dc: &c::DISPATCHER_CONTEXT) -> Option { }; match find_eh_action(dc.HandlerData, &eh_ctx) { EHAction::None => None, - EHAction::Cleanup(lpad) | EHAction::Catch(lpad) => Some(lpad), + EHAction::Cleanup(lpad) | + EHAction::Catch(lpad) => Some(lpad), EHAction::Terminate => intrinsics::abort(), } } diff --git a/src/libproc_macro/Cargo.toml b/src/libproc_macro/Cargo.toml index 99fb1d65cd..7ce65d0fe4 100644 --- a/src/libproc_macro/Cargo.toml +++ b/src/libproc_macro/Cargo.toml @@ -4,12 +4,8 @@ name = "proc_macro" version = "0.0.0" [lib] -name = "proc_macro" path = "lib.rs" crate-type = ["dylib"] [dependencies] -log = { path = "../liblog" } -rustc_plugin = { path = "../librustc_plugin" } syntax = { path = "../libsyntax" } -syntax_pos = { path = "../libsyntax_pos" } diff --git a/src/libproc_macro/lib.rs b/src/libproc_macro/lib.rs index 9e25cb88e0..1d2c64d6d9 100644 --- a/src/libproc_macro/lib.rs +++ b/src/libproc_macro/lib.rs @@ -8,130 +8,158 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -//! # Proc_Macro +//! A support library for macro authors when defining new macros. //! -//! A library for procedural macro writers. +//! This library, provided by the standard distribution, provides the types +//! consumed in the interfaces of procedurally defined macro definitions. +//! Currently the primary use of this crate is to provide the ability to define +//! new custom derive modes through `#[proc_macro_derive]`. //! -//! ## Usage -//! This package provides the `qquote!` macro for syntax creation, and the prelude -//! (at libproc_macro::prelude) provides a number of operations: -//! - `concat`, for concatenating two TokenStreams. -//! - `ident_eq`, for checking if two identifiers are equal regardless of syntax context. -//! - `str_to_token_ident`, for converting an `&str` into a Token. -//! - `keyword_to_token_delim`, for converting a `parse::token::keywords::Keyword` into a -//! Token. -//! - `build_delimited`, for creating a new TokenStream from an existing one and a delimiter -//! by wrapping the TokenStream in the delimiter. -//! - `build_bracket_delimited`, `build_brace_delimited`, and `build_paren_delimited`, for -//! easing the above. -//! - `build_empty_args`, which returns a TokenStream containing `()`. -//! - `lex`, which takes an `&str` and returns the TokenStream it represents. +//! Added recently as part of [RFC 1681] this crate is currently *unstable* and +//! requires the `#![feature(proc_macro_lib)]` directive to use. //! -//! The `qquote!` macro also imports `syntax::ext::proc_macro_shim::prelude::*`, so you -//! will need to `extern crate syntax` for usage. (This is a temporary solution until more -//! of the external API in libproc_macro is stabilized to support the token construction -//! operations that the qausiquoter relies on.) The shim file also provides additional -//! operations, such as `build_block_emitter` (as used in the `cond` example below). -//! -//! ## TokenStreams -//! -//! TokenStreams serve as the basis of the macro system. They are, in essence, vectors of -//! TokenTrees, where indexing treats delimited values as a single term. That is, the term -//! `even(a+c) && even(b)` will be indexibly encoded as `even | (a+c) | even | (b)` where, -//! in reality, `(a+c)` is actually a decorated pointer to `a | + | c`. -//! -//! If a user has a TokenStream that is a single, delimited value, they can use -//! `maybe_delimited` to destruct it and receive the internal vector as a new TokenStream -//! as: -//! ``` -//! `(a+c)`.maybe_delimited() ~> Some(a | + | c)` -//! ``` -//! -//! Check the TokenStream documentation for more information; the structure also provides -//! cheap concatenation and slicing. -//! -//! ## Quasiquotation -//! -//! The quasiquoter creates output that, when run, constructs the tokenstream specified as -//! input. For example, `qquote!(5 + 5)` will produce a program, that, when run, will -//! construct the TokenStream `5 | + | 5`. -//! -//! ### Unquoting -//! -//! Unquoting is currently done as `unquote`, and works by taking the single next -//! TokenTree in the TokenStream as the unquoted term. Ergonomically, `unquote(foo)` works -//! fine, but `unquote foo` is also supported. -//! -//! A simple example might be: -//! -//!``` -//!fn double(tmp: TokenStream) -> TokenStream { -//! qquote!(unquote(tmp) * 2) -//!} -//!``` -//! -//! ### Large Example: Implementing Scheme's `cond` -//! -//! Below is the full implementation of Scheme's `cond` operator. -//! -//! ``` -//! fn cond_rec(input: TokenStream) -> TokenStream { -//! if input.is_empty() { return quote!(); } -//! -//! let next = input.slice(0..1); -//! let rest = input.slice_from(1..); -//! -//! let clause : TokenStream = match next.maybe_delimited() { -//! Some(ts) => ts, -//! _ => panic!("Invalid input"), -//! }; -//! -//! // clause is ([test]) [rhs] -//! if clause.len() < 2 { panic!("Invalid macro usage in cond: {:?}", clause) } -//! -//! let test: TokenStream = clause.slice(0..1); -//! let rhs: TokenStream = clause.slice_from(1..); -//! -//! if ident_eq(&test[0], str_to_ident("else")) || rest.is_empty() { -//! quote!({unquote(rhs)}) -//! } else { -//! quote!({if unquote(test) { unquote(rhs) } else { cond!(unquote(rest)) } }) -//! } -//! } -//! ``` +//! [RFC 1681]: https://github.com/rust-lang/rfcs/blob/master/text/1681-macros-1.1.md //! +//! Note that this crate is intentionally very bare-bones currently. The main +//! type, `TokenStream`, only supports `fmt::Display` and `FromStr` +//! implementations, indicating that it can only go to and come from a string. +//! This functionality is intended to be expanded over time as more surface +//! area for macro authors is stabilized. #![crate_name = "proc_macro"] -#![unstable(feature = "rustc_private", issue = "27812")] -#![feature(plugin_registrar)] -#![crate_type = "dylib"] +#![unstable(feature = "proc_macro_lib", issue = "27812")] #![crate_type = "rlib"] -#![doc(html_logo_url = "https://www.rust-lang.org/logos/rust-logo-128x128-blk-v2.png", - html_favicon_url = "https://doc.rust-lang.org/favicon.ico", - html_root_url = "https://doc.rust-lang.org/nightly/")] +#![crate_type = "dylib"] #![cfg_attr(not(stage0), deny(warnings))] +#![deny(missing_docs)] -#![feature(staged_api)] -#![feature(rustc_diagnostic_macros)] #![feature(rustc_private)] +#![feature(staged_api)] +#![feature(lang_items)] -extern crate rustc_plugin; extern crate syntax; -extern crate syntax_pos; -#[macro_use] extern crate log; -mod qquote; -pub mod build; -pub mod parse; -pub mod prelude; -use qquote::qquote; +use std::fmt; +use std::str::FromStr; + +use syntax::ast; +use syntax::parse; +use syntax::ptr::P; + +/// The main type provided by this crate, representing an abstract stream of +/// tokens. +/// +/// This is both the input and output of `#[proc_macro_derive]` definitions. +/// Currently it's required to be a list of valid Rust items, but this +/// restriction may be lifted in the future. +/// +/// The API of this type is intentionally bare-bones, but it'll be expanded over +/// time! +pub struct TokenStream { + inner: Vec>, +} + +/// Error returned from `TokenStream::from_str`. +#[derive(Debug)] +pub struct LexError { + _inner: (), +} + +/// Permanently unstable internal implementation details of this crate. This +/// should not be used. +/// +/// These methods are used by the rest of the compiler to generate instances of +/// `TokenStream` to hand to macro definitions, as well as consume the output. +/// +/// Note that this module is also intentionally separate from the rest of the +/// crate. This allows the `#[unstable]` directive below to naturally apply to +/// all of the contents. +#[unstable(feature = "proc_macro_internals", issue = "27812")] +#[doc(hidden)] +pub mod __internal { + use std::cell::Cell; + + use syntax::ast; + use syntax::ptr::P; + use syntax::parse::ParseSess; + use super::TokenStream; + + pub fn new_token_stream(item: P) -> TokenStream { + TokenStream { inner: vec![item] } + } -use rustc_plugin::Registry; + pub fn token_stream_items(stream: TokenStream) -> Vec> { + stream.inner + } -// ____________________________________________________________________________________________ -// Main macro definition + pub trait Registry { + fn register_custom_derive(&mut self, + trait_name: &str, + expand: fn(TokenStream) -> TokenStream); + } + + // Emulate scoped_thread_local!() here essentially + thread_local! { + static CURRENT_SESS: Cell<*const ParseSess> = Cell::new(0 as *const _); + } + + pub fn set_parse_sess(sess: &ParseSess, f: F) -> R + where F: FnOnce() -> R + { + struct Reset { prev: *const ParseSess } + + impl Drop for Reset { + fn drop(&mut self) { + CURRENT_SESS.with(|p| p.set(self.prev)); + } + } + + CURRENT_SESS.with(|p| { + let _reset = Reset { prev: p.get() }; + p.set(sess); + f() + }) + } + + pub fn with_parse_sess(f: F) -> R + where F: FnOnce(&ParseSess) -> R + { + let p = CURRENT_SESS.with(|p| p.get()); + assert!(!p.is_null()); + f(unsafe { &*p }) + } +} + +impl FromStr for TokenStream { + type Err = LexError; + + fn from_str(src: &str) -> Result { + __internal::with_parse_sess(|sess| { + let src = src.to_string(); + let name = "".to_string(); + let mut parser = parse::new_parser_from_source_str(sess, name, src); + let mut ret = TokenStream { inner: Vec::new() }; + loop { + match parser.parse_item() { + Ok(Some(item)) => ret.inner.push(item), + Ok(None) => return Ok(ret), + Err(mut err) => { + err.cancel(); + return Err(LexError { _inner: () }) + } + } + } + }) + } +} -#[plugin_registrar] -pub fn plugin_registrar(reg: &mut Registry) { - reg.register_macro("qquote", qquote); +impl fmt::Display for TokenStream { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + for item in self.inner.iter() { + let item = syntax::print::pprust::item_to_string(item); + try!(f.write_str(&item)); + try!(f.write_str("\n")); + } + Ok(()) + } } diff --git a/src/libproc_macro_plugin/Cargo.toml b/src/libproc_macro_plugin/Cargo.toml new file mode 100644 index 0000000000..4bc3f488d3 --- /dev/null +++ b/src/libproc_macro_plugin/Cargo.toml @@ -0,0 +1,15 @@ +[package] +authors = ["The Rust Project Developers"] +name = "proc_macro_plugin" +version = "0.0.0" + +[lib] +path = "lib.rs" +crate-type = ["dylib"] + +[dependencies] +log = { path = "../liblog" } +rustc_plugin = { path = "../librustc_plugin" } +syntax = { path = "../libsyntax" } +syntax_pos = { path = "../libsyntax_pos" } +proc_macro_tokens = { path = "../libproc_macro_tokens" } diff --git a/src/libproc_macro_plugin/lib.rs b/src/libproc_macro_plugin/lib.rs new file mode 100644 index 0000000000..c45762bfb6 --- /dev/null +++ b/src/libproc_macro_plugin/lib.rs @@ -0,0 +1,107 @@ +// Copyright 2016 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +//! # Proc_Macro +//! +//! A library for procedural macro writers. +//! +//! ## Usage +//! This crate provides the `qquote!` macro for syntax creation. +//! +//! The `qquote!` macro imports `syntax::ext::proc_macro_shim::prelude::*`, so you +//! will need to `extern crate syntax` for usage. (This is a temporary solution until more +//! of the external API in libproc_macro_tokens is stabilized to support the token construction +//! operations that the qausiquoter relies on.) The shim file also provides additional +//! operations, such as `build_block_emitter` (as used in the `cond` example below). +//! +//! ## Quasiquotation +//! +//! The quasiquoter creates output that, when run, constructs the tokenstream specified as +//! input. For example, `qquote!(5 + 5)` will produce a program, that, when run, will +//! construct the TokenStream `5 | + | 5`. +//! +//! ### Unquoting +//! +//! Unquoting is currently done as `unquote`, and works by taking the single next +//! TokenTree in the TokenStream as the unquoted term. Ergonomically, `unquote(foo)` works +//! fine, but `unquote foo` is also supported. +//! +//! A simple example might be: +//! +//!``` +//!fn double(tmp: TokenStream) -> TokenStream { +//! qquote!(unquote(tmp) * 2) +//!} +//!``` +//! +//! ### Large Example: Implementing Scheme's `cond` +//! +//! Below is the full implementation of Scheme's `cond` operator. +//! +//! ``` +//! fn cond_rec(input: TokenStream) -> TokenStream { +//! if input.is_empty() { return quote!(); } +//! +//! let next = input.slice(0..1); +//! let rest = input.slice_from(1..); +//! +//! let clause : TokenStream = match next.maybe_delimited() { +//! Some(ts) => ts, +//! _ => panic!("Invalid input"), +//! }; +//! +//! // clause is ([test]) [rhs] +//! if clause.len() < 2 { panic!("Invalid macro usage in cond: {:?}", clause) } +//! +//! let test: TokenStream = clause.slice(0..1); +//! let rhs: TokenStream = clause.slice_from(1..); +//! +//! if ident_eq(&test[0], str_to_ident("else")) || rest.is_empty() { +//! quote!({unquote(rhs)}) +//! } else { +//! quote!({if unquote(test) { unquote(rhs) } else { cond!(unquote(rest)) } }) +//! } +//! } +//! ``` +//! + +#![crate_name = "proc_macro_plugin"] +#![unstable(feature = "rustc_private", issue = "27812")] +#![feature(plugin_registrar)] +#![crate_type = "dylib"] +#![crate_type = "rlib"] +#![doc(html_logo_url = "https://www.rust-lang.org/logos/rust-logo-128x128-blk-v2.png", + html_favicon_url = "https://doc.rust-lang.org/favicon.ico", + html_root_url = "https://doc.rust-lang.org/nightly/")] +#![cfg_attr(not(stage0), deny(warnings))] + +#![feature(staged_api)] +#![feature(rustc_diagnostic_macros)] +#![feature(rustc_private)] + +extern crate rustc_plugin; +extern crate syntax; +extern crate syntax_pos; +extern crate proc_macro_tokens; +#[macro_use] extern crate log; + +mod qquote; + +use qquote::qquote; + +use rustc_plugin::Registry; + +// ____________________________________________________________________________________________ +// Main macro definition + +#[plugin_registrar] +pub fn plugin_registrar(reg: &mut Registry) { + reg.register_macro("qquote", qquote); +} diff --git a/src/libproc_macro/qquote.rs b/src/libproc_macro_plugin/qquote.rs similarity index 98% rename from src/libproc_macro/qquote.rs rename to src/libproc_macro_plugin/qquote.rs index 67d0c77b00..e5a3abc2ea 100644 --- a/src/libproc_macro/qquote.rs +++ b/src/libproc_macro_plugin/qquote.rs @@ -24,12 +24,9 @@ //! TokenStream that resembles the output syntax. //! -extern crate rustc_plugin; -extern crate syntax; -extern crate syntax_pos; +use proc_macro_tokens::build::*; +use proc_macro_tokens::parse::lex; -use build::*; -use parse::lex; use qquote::int_build::*; use syntax::ast::Ident; @@ -51,7 +48,7 @@ pub fn qquote<'cx>(cx: &'cx mut ExtCtxt, sp: Span, tts: &[TokenTree]) let output = qquoter(cx, TokenStream::from_tts(tts.clone().to_owned())); debug!("\nQQ out: {}\n", pprust::tts_to_string(&output.to_tts()[..])); let imports = concat(lex("use syntax::ext::proc_macro_shim::prelude::*;"), - lex("use proc_macro::prelude::*;")); + lex("use proc_macro_tokens::prelude::*;")); build_block_emitter(cx, sp, build_brace_delimited(concat(imports, output))) } @@ -219,7 +216,7 @@ fn convert_complex_tts<'cx>(cx: &'cx mut ExtCtxt, tts: Vec) -> (Bindings, T let sep = build_delim_tok(qdl.delim); - pushes.push(build_mod_call(vec![str_to_ident("proc_macro"), + pushes.push(build_mod_call(vec![str_to_ident("proc_macro_tokens"), str_to_ident("build"), str_to_ident("build_delimited")], concat(from_tokens(vec![Token::Ident(new_id)]), @@ -264,11 +261,8 @@ fn is_qquote(id: Ident) -> bool { } mod int_build { - extern crate syntax; - extern crate syntax_pos; - - use parse::*; - use build::*; + use proc_macro_tokens::build::*; + use proc_macro_tokens::parse::*; use syntax::ast::{self, Ident}; use syntax::codemap::{DUMMY_SP}; diff --git a/src/librustc_macro/Cargo.toml b/src/libproc_macro_tokens/Cargo.toml similarity index 62% rename from src/librustc_macro/Cargo.toml rename to src/libproc_macro_tokens/Cargo.toml index 6b3ee21d9a..2b66d56759 100644 --- a/src/librustc_macro/Cargo.toml +++ b/src/libproc_macro_tokens/Cargo.toml @@ -1,12 +1,13 @@ [package] authors = ["The Rust Project Developers"] -name = "rustc_macro" +name = "proc_macro_tokens" version = "0.0.0" [lib] -name = "rustc_macro" path = "lib.rs" crate-type = ["dylib"] [dependencies] syntax = { path = "../libsyntax" } +syntax_pos = { path = "../libsyntax_pos" } +log = { path = "../liblog" } diff --git a/src/libproc_macro/build.rs b/src/libproc_macro_tokens/build.rs similarity index 100% rename from src/libproc_macro/build.rs rename to src/libproc_macro_tokens/build.rs diff --git a/src/libproc_macro_tokens/lib.rs b/src/libproc_macro_tokens/lib.rs new file mode 100644 index 0000000000..3bfa2fbb29 --- /dev/null +++ b/src/libproc_macro_tokens/lib.rs @@ -0,0 +1,66 @@ +// Copyright 2016 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +//! # Proc_Macro +//! +//! A library for procedural macro writers. +//! +//! ## Usage +//! This crate provides the prelude (at libproc_macro_tokens::prelude), which +//! provides a number of operations: +//! - `concat`, for concatenating two TokenStreams. +//! - `ident_eq`, for checking if two identifiers are equal regardless of syntax context. +//! - `str_to_token_ident`, for converting an `&str` into a Token. +//! - `keyword_to_token_delim`, for converting a `parse::token::keywords::Keyword` into a +//! Token. +//! - `build_delimited`, for creating a new TokenStream from an existing one and a delimiter +//! by wrapping the TokenStream in the delimiter. +//! - `build_bracket_delimited`, `build_brace_delimited`, and `build_paren_delimited`, for +//! easing the above. +//! - `build_empty_args`, which returns a TokenStream containing `()`. +//! - `lex`, which takes an `&str` and returns the TokenStream it represents. +//! +//! ## TokenStreams +//! +//! TokenStreams serve as the basis of the macro system. They are, in essence, vectors of +//! TokenTrees, where indexing treats delimited values as a single term. That is, the term +//! `even(a+c) && even(b)` will be indexibly encoded as `even | (a+c) | even | (b)` where, +//! in reality, `(a+c)` is actually a decorated pointer to `a | + | c`. +//! +//! If a user has a TokenStream that is a single, delimited value, they can use +//! `maybe_delimited` to destruct it and receive the internal vector as a new TokenStream +//! as: +//! ``` +//! `(a+c)`.maybe_delimited() ~> Some(a | + | c)` +//! ``` +//! +//! Check the TokenStream documentation for more information; the structure also provides +//! cheap concatenation and slicing. +//! + +#![crate_name = "proc_macro_tokens"] +#![unstable(feature = "rustc_private", issue = "27812")] +#![crate_type = "dylib"] +#![crate_type = "rlib"] +#![doc(html_logo_url = "https://www.rust-lang.org/logos/rust-logo-128x128-blk-v2.png", + html_favicon_url = "https://doc.rust-lang.org/favicon.ico", + html_root_url = "https://doc.rust-lang.org/nightly/")] +#![cfg_attr(not(stage0), deny(warnings))] + +#![feature(staged_api)] +#![feature(rustc_private)] + +extern crate syntax; +extern crate syntax_pos; +#[macro_use] extern crate log; + +pub mod build; +pub mod parse; +pub mod prelude; diff --git a/src/libproc_macro/parse.rs b/src/libproc_macro_tokens/parse.rs similarity index 100% rename from src/libproc_macro/parse.rs rename to src/libproc_macro_tokens/parse.rs diff --git a/src/libproc_macro/prelude.rs b/src/libproc_macro_tokens/prelude.rs similarity index 100% rename from src/libproc_macro/prelude.rs rename to src/libproc_macro_tokens/prelude.rs diff --git a/src/librand/chacha.rs b/src/librand/chacha.rs index 5fba44a1c3..7dc0d19e6a 100644 --- a/src/librand/chacha.rs +++ b/src/librand/chacha.rs @@ -217,8 +217,8 @@ mod tests { let mut ra: ChaChaRng = SeedableRng::from_seed(&*s); let mut rb: ChaChaRng = SeedableRng::from_seed(&*s); assert!(ra.gen_ascii_chars() - .take(100) - .eq(rb.gen_ascii_chars().take(100))); + .take(100) + .eq(rb.gen_ascii_chars().take(100))); } #[test] @@ -227,8 +227,8 @@ mod tests { let mut ra: ChaChaRng = SeedableRng::from_seed(seed); let mut rb: ChaChaRng = SeedableRng::from_seed(seed); assert!(ra.gen_ascii_chars() - .take(100) - .eq(rb.gen_ascii_chars().take(100))); + .take(100) + .eq(rb.gen_ascii_chars().take(100))); } #[test] @@ -253,17 +253,17 @@ mod tests { let v = (0..16).map(|_| ra.next_u32()).collect::>(); assert_eq!(v, - vec!(0xade0b876, 0x903df1a0, 0xe56a5d40, 0x28bd8653, + vec![0xade0b876, 0x903df1a0, 0xe56a5d40, 0x28bd8653, 0xb819d2bd, 0x1aed8da0, 0xccef36a8, 0xc70d778b, 0x7c5941da, 0x8d485751, 0x3fe02477, 0x374ad8b8, - 0xf4b8436a, 0x1ca11815, 0x69b687c3, 0x8665eeb2)); + 0xf4b8436a, 0x1ca11815, 0x69b687c3, 0x8665eeb2]); let v = (0..16).map(|_| ra.next_u32()).collect::>(); assert_eq!(v, - vec!(0xbee7079f, 0x7a385155, 0x7c97ba98, 0x0d082d73, + vec![0xbee7079f, 0x7a385155, 0x7c97ba98, 0x0d082d73, 0xa0290fcb, 0x6965e348, 0x3e53c612, 0xed7aee32, 0x7621b729, 0x434ee69c, 0xb03371d5, 0xd539d874, - 0x281fed31, 0x45fb0a51, 0x1f0ae1ac, 0x6f4d794b)); + 0x281fed31, 0x45fb0a51, 0x1f0ae1ac, 0x6f4d794b]); let seed: &[_] = &[0, 1, 2, 3, 4, 5, 6, 7]; @@ -280,10 +280,10 @@ mod tests { } assert_eq!(v, - vec!(0xf225c81a, 0x6ab1be57, 0x04d42951, 0x70858036, + vec![0xf225c81a, 0x6ab1be57, 0x04d42951, 0x70858036, 0x49884684, 0x64efec72, 0x4be2d186, 0x3615b384, 0x11cfa18e, 0xd3c50049, 0x75c775f6, 0x434c6530, - 0x2c5bad8f, 0x898881dc, 0x5f1c86d9, 0xc1f8e7f4)); + 0x2c5bad8f, 0x898881dc, 0x5f1c86d9, 0xc1f8e7f4]); } #[test] diff --git a/src/librand/distributions/mod.rs b/src/librand/distributions/mod.rs index 36c9f783ff..41175c81df 100644 --- a/src/librand/distributions/mod.rs +++ b/src/librand/distributions/mod.rs @@ -237,18 +237,10 @@ fn ziggurat(rng: &mut R, // u is either U(-1, 1) or U(0, 1) depending on if this is a // symmetric distribution or not. - let u = if symmetric { - 2.0 * f - 1.0 - } else { - f - }; + let u = if symmetric { 2.0 * f - 1.0 } else { f }; let x = u * x_tab[i]; - let test_x = if symmetric { - x.abs() - } else { - x - }; + let test_x = if symmetric { x.abs() } else { x }; // algebraically equivalent to |u| < x_tab[i+1]/x_tab[i] (or u < x_tab[i+1]/x_tab[i]) if test_x < x_tab[i + 1] { @@ -320,37 +312,37 @@ mod tests { }} } - t!(vec!(Weighted { weight: 1, item: 10 }), + t!(vec![Weighted { weight: 1, item: 10 }], [10]); // skip some - t!(vec!(Weighted { weight: 0, item: 20 }, + t!(vec![Weighted { weight: 0, item: 20 }, Weighted { weight: 2, item: 21 }, Weighted { weight: 0, item: 22 }, - Weighted { weight: 1, item: 23 }), + Weighted { weight: 1, item: 23 }], [21, 21, 23]); // different weights - t!(vec!(Weighted { weight: 4, item: 30 }, - Weighted { weight: 3, item: 31 }), + t!(vec![Weighted { weight: 4, item: 30 }, + Weighted { weight: 3, item: 31 }], [30, 30, 30, 30, 31, 31, 31]); // check that we're binary searching // correctly with some vectors of odd // length. - t!(vec!(Weighted { weight: 1, item: 40 }, + t!(vec![Weighted { weight: 1, item: 40 }, Weighted { weight: 1, item: 41 }, Weighted { weight: 1, item: 42 }, Weighted { weight: 1, item: 43 }, - Weighted { weight: 1, item: 44 }), + Weighted { weight: 1, item: 44 }], [40, 41, 42, 43, 44]); - t!(vec!(Weighted { weight: 1, item: 50 }, + t!(vec![Weighted { weight: 1, item: 50 }, Weighted { weight: 1, item: 51 }, Weighted { weight: 1, item: 52 }, Weighted { weight: 1, item: 53 }, Weighted { weight: 1, item: 54 }, Weighted { weight: 1, item: 55 }, - Weighted { weight: 1, item: 56 }), + Weighted { weight: 1, item: 56 }], [50, 51, 52, 53, 54, 55, 56]); } diff --git a/src/librand/isaac.rs b/src/librand/isaac.rs index e8cc7b5cc2..69d5015f18 100644 --- a/src/librand/isaac.rs +++ b/src/librand/isaac.rs @@ -599,8 +599,8 @@ mod tests { let mut ra: IsaacRng = SeedableRng::from_seed(&s[..]); let mut rb: IsaacRng = SeedableRng::from_seed(&s[..]); assert!(ra.gen_ascii_chars() - .take(100) - .eq(rb.gen_ascii_chars().take(100))); + .take(100) + .eq(rb.gen_ascii_chars().take(100))); } #[test] fn test_rng_64_rand_seeded() { @@ -608,8 +608,8 @@ mod tests { let mut ra: Isaac64Rng = SeedableRng::from_seed(&s[..]); let mut rb: Isaac64Rng = SeedableRng::from_seed(&s[..]); assert!(ra.gen_ascii_chars() - .take(100) - .eq(rb.gen_ascii_chars().take(100))); + .take(100) + .eq(rb.gen_ascii_chars().take(100))); } #[test] @@ -618,8 +618,8 @@ mod tests { let mut ra: IsaacRng = SeedableRng::from_seed(seed); let mut rb: IsaacRng = SeedableRng::from_seed(seed); assert!(ra.gen_ascii_chars() - .take(100) - .eq(rb.gen_ascii_chars().take(100))); + .take(100) + .eq(rb.gen_ascii_chars().take(100))); } #[test] fn test_rng_64_seeded() { @@ -627,8 +627,8 @@ mod tests { let mut ra: Isaac64Rng = SeedableRng::from_seed(seed); let mut rb: Isaac64Rng = SeedableRng::from_seed(seed); assert!(ra.gen_ascii_chars() - .take(100) - .eq(rb.gen_ascii_chars().take(100))); + .take(100) + .eq(rb.gen_ascii_chars().take(100))); } #[test] @@ -662,8 +662,8 @@ mod tests { // Regression test that isaac is actually using the above vector let v = (0..10).map(|_| ra.next_u32()).collect::>(); assert_eq!(v, - vec!(2558573138, 873787463, 263499565, 2103644246, 3595684709, - 4203127393, 264982119, 2765226902, 2737944514, 3900253796)); + vec![2558573138, 873787463, 263499565, 2103644246, 3595684709, + 4203127393, 264982119, 2765226902, 2737944514, 3900253796]); let seed: &[_] = &[12345, 67890, 54321, 9876]; let mut rb: IsaacRng = SeedableRng::from_seed(seed); @@ -674,8 +674,8 @@ mod tests { let v = (0..10).map(|_| rb.next_u32()).collect::>(); assert_eq!(v, - vec!(3676831399, 3183332890, 2834741178, 3854698763, 2717568474, - 1576568959, 3507990155, 179069555, 141456972, 2478885421)); + vec![3676831399, 3183332890, 2834741178, 3854698763, 2717568474, + 1576568959, 3507990155, 179069555, 141456972, 2478885421]); } #[test] #[rustfmt_skip] @@ -685,10 +685,10 @@ mod tests { // Regression test that isaac is actually using the above vector let v = (0..10).map(|_| ra.next_u64()).collect::>(); assert_eq!(v, - vec!(547121783600835980, 14377643087320773276, 17351601304698403469, + vec![547121783600835980, 14377643087320773276, 17351601304698403469, 1238879483818134882, 11952566807690396487, 13970131091560099343, 4469761996653280935, 15552757044682284409, 6860251611068737823, - 13722198873481261842)); + 13722198873481261842]); let seed: &[_] = &[12345, 67890, 54321, 9876]; let mut rb: Isaac64Rng = SeedableRng::from_seed(seed); @@ -699,10 +699,10 @@ mod tests { let v = (0..10).map(|_| rb.next_u64()).collect::>(); assert_eq!(v, - vec!(18143823860592706164, 8491801882678285927, 2699425367717515619, + vec![18143823860592706164, 8491801882678285927, 2699425367717515619, 17196852593171130876, 2606123525235546165, 15790932315217671084, 596345674630742204, 9947027391921273664, 11788097613744130851, - 10391409374914919106)); + 10391409374914919106]); } diff --git a/src/librand/rand_impls.rs b/src/librand/rand_impls.rs index 41ad089ecd..b0d824da3a 100644 --- a/src/librand/rand_impls.rs +++ b/src/librand/rand_impls.rs @@ -203,10 +203,6 @@ tuple_impl!{A, B, C, D, E, F, G, H, I, J, K, L} impl Rand for Option { #[inline] fn rand(rng: &mut R) -> Option { - if rng.gen() { - Some(rng.gen()) - } else { - None - } + if rng.gen() { Some(rng.gen()) } else { None } } } diff --git a/src/librand/reseeding.rs b/src/librand/reseeding.rs index 48395c12fa..b8a65842e2 100644 --- a/src/librand/reseeding.rs +++ b/src/librand/reseeding.rs @@ -138,7 +138,7 @@ mod tests { } } impl Default for Counter { - /// Constructs a `Counter` with initial value zero. + /// Constructs a `Counter` with initial value zero. fn default() -> Counter { Counter { i: 0 } } @@ -169,8 +169,8 @@ mod tests { let mut ra: MyRng = SeedableRng::from_seed((ReseedWithDefault, 2)); let mut rb: MyRng = SeedableRng::from_seed((ReseedWithDefault, 2)); assert!(ra.gen_ascii_chars() - .take(100) - .eq(rb.gen_ascii_chars().take(100))); + .take(100) + .eq(rb.gen_ascii_chars().take(100))); } #[test] diff --git a/src/librustc/cfg/construct.rs b/src/librustc/cfg/construct.rs index 25a7322647..a2fc6e044e 100644 --- a/src/librustc/cfg/construct.rs +++ b/src/librustc/cfg/construct.rs @@ -126,7 +126,7 @@ impl<'a, 'tcx> CFGBuilder<'a, 'tcx> { self.add_ast_node(pat.id, &[pats_exit]) } - PatKind::Vec(ref pre, ref vec, ref post) => { + PatKind::Slice(ref pre, ref vec, ref post) => { let pre_exit = self.pats_all(pre.iter(), pred); let vec_exit = self.pats_all(vec.iter(), pre_exit); let post_exit = self.pats_all(post.iter(), vec_exit); @@ -298,7 +298,7 @@ impl<'a, 'tcx> CFGBuilder<'a, 'tcx> { self.add_unreachable_node() } - hir::ExprVec(ref elems) => { + hir::ExprArray(ref elems) => { self.straightline(expr, pred, elems.iter().map(|e| &**e)) } @@ -311,11 +311,11 @@ impl<'a, 'tcx> CFGBuilder<'a, 'tcx> { } hir::ExprIndex(ref l, ref r) | - hir::ExprBinary(_, ref l, ref r) if self.tcx.is_method_call(expr.id) => { + hir::ExprBinary(_, ref l, ref r) if self.tcx.tables().is_method_call(expr.id) => { self.call(expr, pred, &l, Some(&**r).into_iter()) } - hir::ExprUnary(_, ref e) if self.tcx.is_method_call(expr.id) => { + hir::ExprUnary(_, ref e) if self.tcx.tables().is_method_call(expr.id) => { self.call(expr, pred, &e, None::.iter()) } @@ -372,9 +372,9 @@ impl<'a, 'tcx> CFGBuilder<'a, 'tcx> { func_or_rcvr: &hir::Expr, args: I) -> CFGIndex { let method_call = ty::MethodCall::expr(call_expr.id); - let fn_ty = match self.tcx.tables.borrow().method_map.get(&method_call) { + let fn_ty = match self.tcx.tables().method_map.get(&method_call) { Some(method) => method.ty, - None => self.tcx.expr_ty_adjusted(func_or_rcvr) + None => self.tcx.tables().expr_ty_adjusted(func_or_rcvr) }; let func_or_rcvr_exit = self.expr(func_or_rcvr, pred); @@ -536,7 +536,7 @@ impl<'a, 'tcx> CFGBuilder<'a, 'tcx> { fn add_contained_edge(&mut self, source: CFGIndex, target: CFGIndex) { - let data = CFGEdgeData {exiting_scopes: vec!() }; + let data = CFGEdgeData {exiting_scopes: vec![] }; self.graph.add_edge(source, target, data); } @@ -545,7 +545,7 @@ impl<'a, 'tcx> CFGBuilder<'a, 'tcx> { from_index: CFGIndex, to_loop: LoopScope, to_index: CFGIndex) { - let mut data = CFGEdgeData {exiting_scopes: vec!() }; + let mut data = CFGEdgeData {exiting_scopes: vec![] }; let mut scope = self.tcx.region_maps.node_extent(from_expr.id); let target_scope = self.tcx.region_maps.node_extent(to_loop.loop_id); while scope != target_scope { @@ -559,7 +559,7 @@ impl<'a, 'tcx> CFGBuilder<'a, 'tcx> { _from_expr: &hir::Expr, from_index: CFGIndex) { let mut data = CFGEdgeData { - exiting_scopes: vec!(), + exiting_scopes: vec![], }; for &LoopScope { loop_id: id, .. } in self.loop_scopes.iter().rev() { data.exiting_scopes.push(id); diff --git a/src/librustc/dep_graph/graph.rs b/src/librustc/dep_graph/graph.rs index c42eeead69..fac3586afc 100644 --- a/src/librustc/dep_graph/graph.rs +++ b/src/librustc/dep_graph/graph.rs @@ -51,22 +51,15 @@ impl DepGraph { } } - /// True if we are actually building a dep-graph. If this returns false, - /// then the other methods on this `DepGraph` will have no net effect. - #[inline] - pub fn enabled(&self) -> bool { - self.data.thread.enabled() - } - pub fn query(&self) -> DepGraphQuery { self.data.thread.query() } - pub fn in_ignore<'graph>(&'graph self) -> raii::IgnoreTask<'graph> { + pub fn in_ignore<'graph>(&'graph self) -> Option> { raii::IgnoreTask::new(&self.data.thread) } - pub fn in_task<'graph>(&'graph self, key: DepNode) -> raii::DepTask<'graph> { + pub fn in_task<'graph>(&'graph self, key: DepNode) -> Option> { raii::DepTask::new(&self.data.thread, key) } @@ -85,11 +78,15 @@ impl DepGraph { } pub fn read(&self, v: DepNode) { - self.data.thread.enqueue(DepMessage::Read(v)); + if self.data.thread.is_enqueue_enabled() { + self.data.thread.enqueue(DepMessage::Read(v)); + } } pub fn write(&self, v: DepNode) { - self.data.thread.enqueue(DepMessage::Write(v)); + if self.data.thread.is_enqueue_enabled() { + self.data.thread.enqueue(DepMessage::Write(v)); + } } /// Indicates that a previous work product exists for `v`. This is diff --git a/src/librustc/dep_graph/raii.rs b/src/librustc/dep_graph/raii.rs index e4f572902f..e39797599a 100644 --- a/src/librustc/dep_graph/raii.rs +++ b/src/librustc/dep_graph/raii.rs @@ -19,15 +19,21 @@ pub struct DepTask<'graph> { impl<'graph> DepTask<'graph> { pub fn new(data: &'graph DepGraphThreadData, key: DepNode) - -> DepTask<'graph> { - data.enqueue(DepMessage::PushTask(key.clone())); - DepTask { data: data, key: Some(key) } + -> Option> { + if data.is_enqueue_enabled() { + data.enqueue(DepMessage::PushTask(key.clone())); + Some(DepTask { data: data, key: Some(key) }) + } else { + None + } } } impl<'graph> Drop for DepTask<'graph> { fn drop(&mut self) { - self.data.enqueue(DepMessage::PopTask(self.key.take().unwrap())); + if self.data.is_enqueue_enabled() { + self.data.enqueue(DepMessage::PopTask(self.key.take().unwrap())); + } } } @@ -36,15 +42,21 @@ pub struct IgnoreTask<'graph> { } impl<'graph> IgnoreTask<'graph> { - pub fn new(data: &'graph DepGraphThreadData) -> IgnoreTask<'graph> { - data.enqueue(DepMessage::PushIgnore); - IgnoreTask { data: data } + pub fn new(data: &'graph DepGraphThreadData) -> Option> { + if data.is_enqueue_enabled() { + data.enqueue(DepMessage::PushIgnore); + Some(IgnoreTask { data: data }) + } else { + None + } } } impl<'graph> Drop for IgnoreTask<'graph> { fn drop(&mut self) { - self.data.enqueue(DepMessage::PopIgnore); + if self.data.is_enqueue_enabled() { + self.data.enqueue(DepMessage::PopIgnore); + } } } diff --git a/src/librustc/dep_graph/shadow.rs b/src/librustc/dep_graph/shadow.rs index 72a321425e..06def4bf19 100644 --- a/src/librustc/dep_graph/shadow.rs +++ b/src/librustc/dep_graph/shadow.rs @@ -64,6 +64,11 @@ impl ShadowGraph { } } + #[inline] + pub fn enabled(&self) -> bool { + ENABLED + } + pub fn enqueue(&self, message: &DepMessage) { if ENABLED { match self.stack.borrow_state() { diff --git a/src/librustc/dep_graph/thread.rs b/src/librustc/dep_graph/thread.rs index 90c42d66b7..9f755cf86e 100644 --- a/src/librustc/dep_graph/thread.rs +++ b/src/librustc/dep_graph/thread.rs @@ -88,15 +88,24 @@ impl DepGraphThreadData { } } + /// True if we are actually building the full dep-graph. #[inline] - pub fn enabled(&self) -> bool { + pub fn is_fully_enabled(&self) -> bool { self.enabled } + /// True if (a) we are actually building the full dep-graph, or (b) we are + /// only enqueuing messages in order to sanity-check them (which happens + /// when debug assertions are enabled). + #[inline] + pub fn is_enqueue_enabled(&self) -> bool { + self.is_fully_enabled() || self.shadow_graph.enabled() + } + /// Sends the current batch of messages to the thread. Installs a /// new vector of messages. fn swap(&self) { - assert!(self.enabled, "should never swap if not enabled"); + assert!(self.is_fully_enabled(), "should never swap if not fully enabled"); // should be a buffer waiting for us (though of course we may // have to wait for depgraph thread to finish processing the @@ -112,7 +121,7 @@ impl DepGraphThreadData { } pub fn query(&self) -> DepGraphQuery { - assert!(self.enabled, "cannot query if dep graph construction not enabled"); + assert!(self.is_fully_enabled(), "should never query if not fully enabled"); self.enqueue(DepMessage::Query); self.swap(); self.query_in.recv().unwrap() @@ -122,9 +131,9 @@ impl DepGraphThreadData { /// the buffer is full, this may swap.) #[inline] pub fn enqueue(&self, message: DepMessage) { + assert!(self.is_enqueue_enabled(), "should never enqueue if not enqueue-enabled"); self.shadow_graph.enqueue(&message); - - if self.enabled { + if self.is_fully_enabled() { self.enqueue_enabled(message); } } diff --git a/src/librustc/diagnostics.rs b/src/librustc/diagnostics.rs index 12a1a42552..465a09505e 100644 --- a/src/librustc/diagnostics.rs +++ b/src/librustc/diagnostics.rs @@ -1407,6 +1407,23 @@ fn make_child<'elve>(x: &mut &'elve isize, y: &mut &'elve isize) { ``` "##, +E0317: r##" +This error occurs when an `if` expression without an `else` block is used in a +context where a type other than `()` is expected, for example a `let` +expression: + +```compile_fail,E0317 +fn main() { + let x = 5; + let a = if x == 5 { 1 }; +} +``` + +An `if` expression without an `else` block has the type `()`, so this is a type +error. To resolve it, add an `else` block having the same type as the `if` +block. +"##, + E0398: r##" In Rust 1.3, the default object lifetime bounds are expected to change, as described in RFC #1156 [1]. You are getting a warning because the compiler diff --git a/src/librustc/hir/def.rs b/src/librustc/hir/def.rs index dec8ea8a29..8b9cee1d2f 100644 --- a/src/librustc/hir/def.rs +++ b/src/librustc/hir/def.rs @@ -13,34 +13,46 @@ use util::nodemap::NodeMap; use syntax::ast; use hir; +#[derive(Clone, Copy, PartialEq, Eq, RustcEncodable, RustcDecodable, Hash, Debug)] +pub enum CtorKind { + // Constructor function automatically created by a tuple struct/variant. + Fn, + // Constructor constant automatically created by a unit struct/variant. + Const, + // Unusable name in value namespace created by a struct variant. + Fictive, +} + #[derive(Clone, Copy, PartialEq, Eq, RustcEncodable, RustcDecodable, Hash, Debug)] pub enum Def { - Fn(DefId), - SelfTy(Option /* trait */, Option /* impl */), + // Type namespace Mod(DefId), - Static(DefId, bool /* is_mutbl */), - Const(DefId), - AssociatedConst(DefId), - Local(DefId), - Variant(DefId), + Struct(DefId), // DefId refers to NodeId of the struct itself + Union(DefId), Enum(DefId), + Variant(DefId), + Trait(DefId), TyAlias(DefId), AssociatedTy(DefId), - Trait(DefId), PrimTy(hir::PrimTy), TyParam(DefId), - Upvar(DefId, // def id of closed over local - usize, // index in the freevars list of the closure - ast::NodeId), // expr node that creates the closure + SelfTy(Option /* trait */, Option /* impl */), - // If Def::Struct lives in type namespace it denotes a struct item and its DefId refers - // to NodeId of the struct itself. - // If Def::Struct lives in value namespace (e.g. tuple struct, unit struct expressions) - // it denotes a constructor and its DefId refers to NodeId of the struct's constructor. - Struct(DefId), - Union(DefId), - Label(ast::NodeId), + // Value namespace + Fn(DefId), + Const(DefId), + Static(DefId, bool /* is_mutbl */), + StructCtor(DefId, CtorKind), // DefId refers to NodeId of the struct's constructor + VariantCtor(DefId, CtorKind), Method(DefId), + AssociatedConst(DefId), + Local(DefId), + Upvar(DefId, // def id of closed over local + usize, // index in the freevars list of the closure + ast::NodeId), // expr node that creates the closure + Label(ast::NodeId), + + // Both namespaces Err, } @@ -93,18 +105,35 @@ pub type ExportMap = NodeMap>; #[derive(Copy, Clone, RustcEncodable, RustcDecodable)] pub struct Export { - pub name: ast::Name, // The name of the target. - pub def_id: DefId, // The definition of the target. + pub name: ast::Name, // The name of the target. + pub def: Def, // The definition of the target. +} + +impl CtorKind { + pub fn from_ast(vdata: &ast::VariantData) -> CtorKind { + match *vdata { + ast::VariantData::Tuple(..) => CtorKind::Fn, + ast::VariantData::Unit(..) => CtorKind::Const, + ast::VariantData::Struct(..) => CtorKind::Fictive, + } + } + pub fn from_hir(vdata: &hir::VariantData) -> CtorKind { + match *vdata { + hir::VariantData::Tuple(..) => CtorKind::Fn, + hir::VariantData::Unit(..) => CtorKind::Const, + hir::VariantData::Struct(..) => CtorKind::Fictive, + } + } } impl Def { pub fn def_id(&self) -> DefId { match *self { Def::Fn(id) | Def::Mod(id) | Def::Static(id, _) | - Def::Variant(id) | Def::Enum(id) | Def::TyAlias(id) | Def::AssociatedTy(id) | - Def::TyParam(id) | Def::Struct(id) | Def::Union(id) | Def::Trait(id) | - Def::Method(id) | Def::Const(id) | Def::AssociatedConst(id) | - Def::Local(id) | Def::Upvar(id, ..) => { + Def::Variant(id) | Def::VariantCtor(id, ..) | Def::Enum(id) | Def::TyAlias(id) | + Def::AssociatedTy(id) | Def::TyParam(id) | Def::Struct(id) | Def::StructCtor(id, ..) | + Def::Union(id) | Def::Trait(id) | Def::Method(id) | Def::Const(id) | + Def::AssociatedConst(id) | Def::Local(id) | Def::Upvar(id, ..) => { id } @@ -123,10 +152,16 @@ impl Def { Def::Mod(..) => "module", Def::Static(..) => "static", Def::Variant(..) => "variant", + Def::VariantCtor(.., CtorKind::Fn) => "tuple variant", + Def::VariantCtor(.., CtorKind::Const) => "unit variant", + Def::VariantCtor(.., CtorKind::Fictive) => "struct variant", Def::Enum(..) => "enum", - Def::TyAlias(..) => "type", + Def::TyAlias(..) => "type alias", Def::AssociatedTy(..) => "associated type", Def::Struct(..) => "struct", + Def::StructCtor(.., CtorKind::Fn) => "tuple struct", + Def::StructCtor(.., CtorKind::Const) => "unit struct", + Def::StructCtor(.., CtorKind::Fictive) => bug!("impossible struct constructor"), Def::Union(..) => "union", Def::Trait(..) => "trait", Def::Method(..) => "method", diff --git a/src/librustc/hir/intravisit.rs b/src/librustc/hir/intravisit.rs index 726e4e53e2..b1771f52da 100644 --- a/src/librustc/hir/intravisit.rs +++ b/src/librustc/hir/intravisit.rs @@ -394,7 +394,7 @@ pub fn walk_ty<'v, V: Visitor<'v>>(visitor: &mut V, typ: &'v Ty) { visitor.visit_id(typ.id); match typ.node { - TyVec(ref ty) => { + TySlice(ref ty) => { visitor.visit_ty(ty) } TyPtr(ref mutable_type) => { @@ -422,7 +422,7 @@ pub fn walk_ty<'v, V: Visitor<'v>>(visitor: &mut V, typ: &'v Ty) { visitor.visit_ty(ty); walk_list!(visitor, visit_ty_param_bound, bounds); } - TyFixedLengthVec(ref ty, ref expression) => { + TyArray(ref ty, ref expression) => { visitor.visit_ty(ty); visitor.visit_expr(expression) } @@ -520,7 +520,7 @@ pub fn walk_pat<'v, V: Visitor<'v>>(visitor: &mut V, pattern: &'v Pat) { visitor.visit_expr(upper_bound) } PatKind::Wild => (), - PatKind::Vec(ref prepatterns, ref slice_pattern, ref postpatterns) => { + PatKind::Slice(ref prepatterns, ref slice_pattern, ref postpatterns) => { walk_list!(visitor, visit_pat, prepatterns); walk_list!(visitor, visit_pat, slice_pattern); walk_list!(visitor, visit_pat, postpatterns); @@ -749,7 +749,7 @@ pub fn walk_expr<'v, V: Visitor<'v>>(visitor: &mut V, expression: &'v Expr) { ExprBox(ref subexpression) => { visitor.visit_expr(subexpression) } - ExprVec(ref subexpressions) => { + ExprArray(ref subexpressions) => { walk_list!(visitor, visit_expr, subexpressions); } ExprRepeat(ref element, ref count) => { diff --git a/src/librustc/hir/lowering.rs b/src/librustc/hir/lowering.rs index 29dedeeeb0..e1fec898e4 100644 --- a/src/librustc/hir/lowering.rs +++ b/src/librustc/hir/lowering.rs @@ -94,13 +94,7 @@ pub fn lower_crate(sess: &Session, let _ignore = sess.dep_graph.in_ignore(); LoweringContext { - crate_root: if std_inject::no_core(krate) { - None - } else if std_inject::no_std(krate) { - Some("core") - } else { - Some("std") - }, + crate_root: std_inject::injected_crate_name(krate), sess: sess, parent_def: None, resolver: resolver, @@ -130,7 +124,6 @@ impl<'a> LoweringContext<'a> { hir::Crate { module: self.lower_mod(&c.module), attrs: self.lower_attrs(&c.attrs), - config: c.config.clone().into(), span: c.span, exported_macros: c.exported_macros.iter().map(|m| self.lower_macro_def(m)).collect(), items: items, @@ -222,17 +215,16 @@ impl<'a> LoweringContext<'a> { } fn lower_ty(&mut self, t: &Ty) -> P { - use syntax::ast::TyKind::*; P(hir::Ty { id: t.id, node: match t.node { - Infer | ImplicitSelf => hir::TyInfer, - Vec(ref ty) => hir::TyVec(self.lower_ty(ty)), - Ptr(ref mt) => hir::TyPtr(self.lower_mt(mt)), - Rptr(ref region, ref mt) => { + TyKind::Infer | TyKind::ImplicitSelf => hir::TyInfer, + TyKind::Slice(ref ty) => hir::TySlice(self.lower_ty(ty)), + TyKind::Ptr(ref mt) => hir::TyPtr(self.lower_mt(mt)), + TyKind::Rptr(ref region, ref mt) => { hir::TyRptr(self.lower_opt_lifetime(region), self.lower_mt(mt)) } - BareFn(ref f) => { + TyKind::BareFn(ref f) => { hir::TyBareFn(P(hir::BareFnTy { lifetimes: self.lower_lifetime_defs(&f.lifetimes), unsafety: self.lower_unsafety(f.unsafety), @@ -240,12 +232,14 @@ impl<'a> LoweringContext<'a> { decl: self.lower_fn_decl(&f.decl), })) } - Never => hir::TyNever, - Tup(ref tys) => hir::TyTup(tys.iter().map(|ty| self.lower_ty(ty)).collect()), - Paren(ref ty) => { + TyKind::Never => hir::TyNever, + TyKind::Tup(ref tys) => { + hir::TyTup(tys.iter().map(|ty| self.lower_ty(ty)).collect()) + } + TyKind::Paren(ref ty) => { return self.lower_ty(ty); } - Path(ref qself, ref path) => { + TyKind::Path(ref qself, ref path) => { let qself = qself.as_ref().map(|&QSelf { ref ty, position }| { hir::QSelf { ty: self.lower_ty(ty), @@ -254,22 +248,22 @@ impl<'a> LoweringContext<'a> { }); hir::TyPath(qself, self.lower_path(path)) } - ObjectSum(ref ty, ref bounds) => { + TyKind::ObjectSum(ref ty, ref bounds) => { hir::TyObjectSum(self.lower_ty(ty), self.lower_bounds(bounds)) } - FixedLengthVec(ref ty, ref e) => { - hir::TyFixedLengthVec(self.lower_ty(ty), self.lower_expr(e)) + TyKind::Array(ref ty, ref e) => { + hir::TyArray(self.lower_ty(ty), self.lower_expr(e)) } - Typeof(ref expr) => { + TyKind::Typeof(ref expr) => { hir::TyTypeof(self.lower_expr(expr)) } - PolyTraitRef(ref bounds) => { + TyKind::PolyTraitRef(ref bounds) => { hir::TyPolyTraitRef(self.lower_bounds(bounds)) } - ImplTrait(ref bounds) => { + TyKind::ImplTrait(ref bounds) => { hir::TyImplTrait(self.lower_bounds(bounds)) } - Mac(_) => panic!("TyMac should have been expanded by now."), + TyKind::Mac(_) => panic!("TyMac should have been expanded by now."), }, span: t.span, }) @@ -406,6 +400,7 @@ impl<'a> LoweringContext<'a> { bounds: self.lower_bounds(&tp.bounds), default: tp.default.as_ref().map(|x| self.lower_ty(x)), span: tp.span, + pure_wrt_drop: tp.attrs.iter().any(|attr| attr.check_name("may_dangle")), } } @@ -425,6 +420,7 @@ impl<'a> LoweringContext<'a> { hir::LifetimeDef { lifetime: self.lower_lifetime(&l.lifetime), bounds: self.lower_lifetimes(&l.bounds), + pure_wrt_drop: l.attrs.iter().any(|attr| attr.check_name("may_dangle")), } } @@ -546,6 +542,7 @@ impl<'a> LoweringContext<'a> { name: respan(f.ident.span, f.ident.node.name), expr: self.lower_expr(&f.expr), span: f.span, + is_shorthand: f.is_shorthand, } } @@ -719,8 +716,6 @@ impl<'a> LoweringContext<'a> { id: m.id, span: m.span, imported_from: m.imported_from.map(|x| x.name), - export: m.export, - use_locally: m.use_locally, allow_internal_unstable: m.allow_internal_unstable, body: m.body.clone().into(), } @@ -854,10 +849,9 @@ impl<'a> LoweringContext<'a> { }) } PatKind::Lit(ref e) => hir::PatKind::Lit(self.lower_expr(e)), - PatKind::TupleStruct(ref pth, ref pats, ddpos) => { - hir::PatKind::TupleStruct(self.lower_path(pth), - pats.iter().map(|x| self.lower_pat(x)).collect(), - ddpos) + PatKind::TupleStruct(ref path, ref pats, ddpos) => { + hir::PatKind::TupleStruct(self.lower_path(path), + pats.iter().map(|x| self.lower_pat(x)).collect(), ddpos) } PatKind::Path(ref opt_qself, ref path) => { let opt_qself = opt_qself.as_ref().map(|qself| { @@ -891,8 +885,8 @@ impl<'a> LoweringContext<'a> { PatKind::Range(ref e1, ref e2) => { hir::PatKind::Range(self.lower_expr(e1), self.lower_expr(e2)) } - PatKind::Vec(ref before, ref slice, ref after) => { - hir::PatKind::Vec(before.iter().map(|x| self.lower_pat(x)).collect(), + PatKind::Slice(ref before, ref slice, ref after) => { + hir::PatKind::Slice(before.iter().map(|x| self.lower_pat(x)).collect(), slice.as_ref().map(|x| self.lower_pat(x)), after.iter().map(|x| self.lower_pat(x)).collect()) } @@ -1031,7 +1025,7 @@ impl<'a> LoweringContext<'a> { } ExprKind::Vec(ref exprs) => { - hir::ExprVec(exprs.iter().map(|x| self.lower_expr(x)).collect()) + hir::ExprArray(exprs.iter().map(|x| self.lower_expr(x)).collect()) } ExprKind::Repeat(ref expr, ref count) => { let expr = self.lower_expr(expr); @@ -1214,38 +1208,32 @@ impl<'a> LoweringContext<'a> { ExprKind::Break(opt_ident) => hir::ExprBreak(self.lower_opt_sp_ident(opt_ident)), ExprKind::Continue(opt_ident) => hir::ExprAgain(self.lower_opt_sp_ident(opt_ident)), ExprKind::Ret(ref e) => hir::ExprRet(e.as_ref().map(|x| self.lower_expr(x))), - ExprKind::InlineAsm(InlineAsm { - ref inputs, - ref outputs, - ref asm, - asm_str_style, - ref clobbers, - volatile, - alignstack, - dialect, - expn_id, - }) => hir::ExprInlineAsm(hir::InlineAsm { - inputs: inputs.iter().map(|&(ref c, _)| c.clone()).collect(), - outputs: outputs.iter() - .map(|out| { - hir::InlineAsmOutput { - constraint: out.constraint.clone(), - is_rw: out.is_rw, - is_indirect: out.is_indirect, - } - }) - .collect(), - asm: asm.clone(), - asm_str_style: asm_str_style, - clobbers: clobbers.clone().into(), - volatile: volatile, - alignstack: alignstack, - dialect: dialect, - expn_id: expn_id, - }, outputs.iter().map(|out| self.lower_expr(&out.expr)).collect(), - inputs.iter().map(|&(_, ref input)| self.lower_expr(input)).collect()), + ExprKind::InlineAsm(ref asm) => { + let hir_asm = hir::InlineAsm { + inputs: asm.inputs.iter().map(|&(ref c, _)| c.clone()).collect(), + outputs: asm.outputs.iter().map(|out| { + hir::InlineAsmOutput { + constraint: out.constraint.clone(), + is_rw: out.is_rw, + is_indirect: out.is_indirect, + } + }).collect(), + asm: asm.asm.clone(), + asm_str_style: asm.asm_str_style, + clobbers: asm.clobbers.clone().into(), + volatile: asm.volatile, + alignstack: asm.alignstack, + dialect: asm.dialect, + expn_id: asm.expn_id, + }; + let outputs = + asm.outputs.iter().map(|out| self.lower_expr(&out.expr)).collect(); + let inputs = + asm.inputs.iter().map(|&(_, ref input)| self.lower_expr(input)).collect(); + hir::ExprInlineAsm(P(hir_asm), outputs, inputs) + } ExprKind::Struct(ref path, ref fields, ref maybe_expr) => { - hir::ExprStruct(self.lower_path(path), + hir::ExprStruct(P(self.lower_path(path)), fields.iter().map(|x| self.lower_field(x)).collect(), maybe_expr.as_ref().map(|x| self.lower_expr(x))) } @@ -1688,6 +1676,7 @@ impl<'a> LoweringContext<'a> { }, span: span, expr: expr, + is_shorthand: false, } } @@ -1748,7 +1737,7 @@ impl<'a> LoweringContext<'a> { e: Option>, attrs: ThinVec) -> P { let def = self.resolver.resolve_generated_global_path(&path, false); - let expr = self.expr(sp, hir::ExprStruct(path, fields, e), attrs); + let expr = self.expr(sp, hir::ExprStruct(P(path), fields, e), attrs); self.resolver.record_resolution(expr.id, def); expr } diff --git a/src/librustc/hir/map/def_collector.rs b/src/librustc/hir/map/def_collector.rs index b0a717e18f..421843a7f1 100644 --- a/src/librustc/hir/map/def_collector.rs +++ b/src/librustc/hir/map/def_collector.rs @@ -17,32 +17,41 @@ use hir::def_id::{CRATE_DEF_INDEX, DefId, DefIndex}; use middle::cstore::InlinedItem; use syntax::ast::*; +use syntax::ext::hygiene::Mark; use syntax::visit; -use syntax::parse::token; +use syntax::parse::token::{self, keywords}; /// Creates def ids for nodes in the HIR. -pub struct DefCollector<'ast> { +pub struct DefCollector<'a> { // If we are walking HIR (c.f., AST), we need to keep a reference to the // crate. - hir_crate: Option<&'ast hir::Crate>, - definitions: &'ast mut Definitions, + hir_crate: Option<&'a hir::Crate>, + definitions: &'a mut Definitions, parent_def: Option, + pub visit_macro_invoc: Option<&'a mut FnMut(MacroInvocationData)>, } -impl<'ast> DefCollector<'ast> { - pub fn new(definitions: &'ast mut Definitions) -> DefCollector<'ast> { +pub struct MacroInvocationData { + pub mark: Mark, + pub def_index: DefIndex, + pub const_integer: bool, +} + +impl<'a> DefCollector<'a> { + pub fn new(definitions: &'a mut Definitions) -> Self { DefCollector { hir_crate: None, definitions: definitions, parent_def: None, + visit_macro_invoc: None, } } pub fn extend(parent_node: NodeId, parent_def_path: DefPath, parent_def_id: DefId, - definitions: &'ast mut Definitions) - -> DefCollector<'ast> { + definitions: &'a mut Definitions) + -> Self { let mut collector = DefCollector::new(definitions); assert_eq!(parent_def_path.krate, parent_def_id.krate); @@ -65,7 +74,7 @@ impl<'ast> DefCollector<'ast> { self.create_def_with_parent(Some(CRATE_DEF_INDEX), DUMMY_NODE_ID, DefPathData::Misc); } - pub fn walk_item(&mut self, ii: &'ast InlinedItem, krate: &'ast hir::Crate) { + pub fn walk_item(&mut self, ii: &'a InlinedItem, krate: &'a hir::Crate) { self.hir_crate = Some(krate); ii.visit(self); } @@ -84,29 +93,28 @@ impl<'ast> DefCollector<'ast> { self.definitions.create_def_with_parent(parent, node_id, data) } - fn with_parent(&mut self, parent_def: DefIndex, f: F) { + pub fn with_parent(&mut self, parent_def: DefIndex, f: F) { let parent = self.parent_def; self.parent_def = Some(parent_def); f(self); self.parent_def = parent; } - fn visit_ast_const_integer(&mut self, expr: &Expr) { - // Find the node which will be used after lowering. - if let ExprKind::Paren(ref inner) = expr.node { - return self.visit_ast_const_integer(inner); - } - - // FIXME(eddyb) Closures should have separate - // function definition IDs and expression IDs. - if let ExprKind::Closure(..) = expr.node { - return; + pub fn visit_ast_const_integer(&mut self, expr: &Expr) { + match expr.node { + // Find the node which will be used after lowering. + ExprKind::Paren(ref inner) => return self.visit_ast_const_integer(inner), + ExprKind::Mac(..) => return self.visit_macro_invoc(expr.id, true), + // FIXME(eddyb) Closures should have separate + // function definition IDs and expression IDs. + ExprKind::Closure(..) => return, + _ => {} } self.create_def(expr.id, DefPathData::Initializer); } - fn visit_hir_const_integer(&mut self, expr: &'ast hir::Expr) { + fn visit_hir_const_integer(&mut self, expr: &hir::Expr) { // FIXME(eddyb) Closures should have separate // function definition IDs and expression IDs. if let hir::ExprClosure(..) = expr.node { @@ -115,9 +123,19 @@ impl<'ast> DefCollector<'ast> { self.create_def(expr.id, DefPathData::Initializer); } + + fn visit_macro_invoc(&mut self, id: NodeId, const_integer: bool) { + if let Some(ref mut visit) = self.visit_macro_invoc { + visit(MacroInvocationData { + mark: Mark::from_placeholder_id(id), + const_integer: const_integer, + def_index: self.parent_def.unwrap(), + }) + } + } } -impl<'ast> visit::Visitor for DefCollector<'ast> { +impl<'a> visit::Visitor for DefCollector<'a> { fn visit_item(&mut self, i: &Item) { debug!("visit_item: {:?}", i); @@ -129,10 +147,14 @@ impl<'ast> visit::Visitor for DefCollector<'ast> { ItemKind::Enum(..) | ItemKind::Struct(..) | ItemKind::Union(..) | ItemKind::Trait(..) | ItemKind::ExternCrate(..) | ItemKind::ForeignMod(..) | ItemKind::Ty(..) => DefPathData::TypeNs(i.ident.name.as_str()), + ItemKind::Mod(..) if i.ident == keywords::Invalid.ident() => { + return visit::walk_item(self, i); + } ItemKind::Mod(..) => DefPathData::Module(i.ident.name.as_str()), ItemKind::Static(..) | ItemKind::Const(..) | ItemKind::Fn(..) => DefPathData::ValueNs(i.ident.name.as_str()), - ItemKind::Mac(..) => DefPathData::MacroDef(i.ident.name.as_str()), + ItemKind::Mac(..) if i.id == DUMMY_NODE_ID => return, // Scope placeholder + ItemKind::Mac(..) => return self.visit_macro_invoc(i.id, false), ItemKind::Use(..) => DefPathData::Misc, }; let def = self.create_def(i.id, def_data); @@ -198,7 +220,7 @@ impl<'ast> visit::Visitor for DefCollector<'ast> { TraitItemKind::Method(..) | TraitItemKind::Const(..) => DefPathData::ValueNs(ti.ident.name.as_str()), TraitItemKind::Type(..) => DefPathData::TypeNs(ti.ident.name.as_str()), - TraitItemKind::Macro(..) => DefPathData::MacroDef(ti.ident.name.as_str()), + TraitItemKind::Macro(..) => return self.visit_macro_invoc(ti.id, false), }; let def = self.create_def(ti.id, def_data); @@ -216,7 +238,7 @@ impl<'ast> visit::Visitor for DefCollector<'ast> { ImplItemKind::Method(..) | ImplItemKind::Const(..) => DefPathData::ValueNs(ii.ident.name.as_str()), ImplItemKind::Type(..) => DefPathData::TypeNs(ii.ident.name.as_str()), - ImplItemKind::Macro(..) => DefPathData::MacroDef(ii.ident.name.as_str()), + ImplItemKind::Macro(..) => return self.visit_macro_invoc(ii.id, false), }; let def = self.create_def(ii.id, def_data); @@ -232,9 +254,13 @@ impl<'ast> visit::Visitor for DefCollector<'ast> { fn visit_pat(&mut self, pat: &Pat) { let parent_def = self.parent_def; - if let PatKind::Ident(_, id, _) = pat.node { - let def = self.create_def(pat.id, DefPathData::Binding(id.node.name.as_str())); - self.parent_def = Some(def); + match pat.node { + PatKind::Mac(..) => return self.visit_macro_invoc(pat.id, false), + PatKind::Ident(_, id, _) => { + let def = self.create_def(pat.id, DefPathData::Binding(id.node.name.as_str())); + self.parent_def = Some(def); + } + _ => {} } visit::walk_pat(self, pat); @@ -244,13 +270,14 @@ impl<'ast> visit::Visitor for DefCollector<'ast> { fn visit_expr(&mut self, expr: &Expr) { let parent_def = self.parent_def; - if let ExprKind::Repeat(_, ref count) = expr.node { - self.visit_ast_const_integer(count); - } - - if let ExprKind::Closure(..) = expr.node { - let def = self.create_def(expr.id, DefPathData::ClosureExpr); - self.parent_def = Some(def); + match expr.node { + ExprKind::Mac(..) => return self.visit_macro_invoc(expr.id, false), + ExprKind::Repeat(_, ref count) => self.visit_ast_const_integer(count), + ExprKind::Closure(..) => { + let def = self.create_def(expr.id, DefPathData::ClosureExpr); + self.parent_def = Some(def); + } + _ => {} } visit::walk_expr(self, expr); @@ -258,11 +285,13 @@ impl<'ast> visit::Visitor for DefCollector<'ast> { } fn visit_ty(&mut self, ty: &Ty) { - if let TyKind::FixedLengthVec(_, ref length) = ty.node { - self.visit_ast_const_integer(length); - } - if let TyKind::ImplTrait(..) = ty.node { - self.create_def(ty.id, DefPathData::ImplTrait); + match ty.node { + TyKind::Mac(..) => return self.visit_macro_invoc(ty.id, false), + TyKind::Array(_, ref length) => self.visit_ast_const_integer(length), + TyKind::ImplTrait(..) => { + self.create_def(ty.id, DefPathData::ImplTrait); + } + _ => {} } visit::walk_ty(self, ty); } @@ -274,6 +303,13 @@ impl<'ast> visit::Visitor for DefCollector<'ast> { fn visit_macro_def(&mut self, macro_def: &MacroDef) { self.create_def(macro_def.id, DefPathData::MacroDef(macro_def.ident.name.as_str())); } + + fn visit_stmt(&mut self, stmt: &Stmt) { + match stmt.node { + StmtKind::Mac(..) => self.visit_macro_invoc(stmt.id, false), + _ => visit::walk_stmt(self, stmt), + } + } } // We walk the HIR rather than the AST when reading items from metadata. @@ -413,7 +449,7 @@ impl<'ast> intravisit::Visitor<'ast> for DefCollector<'ast> { } fn visit_ty(&mut self, ty: &'ast hir::Ty) { - if let hir::TyFixedLengthVec(_, ref length) = ty.node { + if let hir::TyArray(_, ref length) = ty.node { self.visit_hir_const_integer(length); } if let hir::TyImplTrait(..) = ty.node { diff --git a/src/librustc/hir/map/definitions.rs b/src/librustc/hir/map/definitions.rs index 3e77c09139..e8b3714bbe 100644 --- a/src/librustc/hir/map/definitions.rs +++ b/src/librustc/hir/map/definitions.rs @@ -9,12 +9,11 @@ // except according to those terms. use hir::def_id::{CrateNum, DefId, DefIndex, LOCAL_CRATE}; -use hir::map::def_collector::DefCollector; use rustc_data_structures::fnv::FnvHashMap; use std::fmt::Write; use std::hash::{Hash, Hasher}; use std::collections::hash_map::DefaultHasher; -use syntax::{ast, visit}; +use syntax::ast; use syntax::parse::token::{self, InternedString}; use ty::TyCtxt; use util::nodemap::NodeMap; @@ -225,12 +224,6 @@ impl Definitions { } } - pub fn collect(&mut self, krate: &ast::Crate) { - let mut def_collector = DefCollector::new(self); - def_collector.collect_root(); - visit::walk_crate(&mut def_collector, krate); - } - /// Get the number of definitions. pub fn len(&self) -> usize { self.data.len() diff --git a/src/librustc/hir/map/mod.rs b/src/librustc/hir/map/mod.rs index b351bd427a..39114ec423 100644 --- a/src/librustc/hir/map/mod.rs +++ b/src/librustc/hir/map/mod.rs @@ -11,7 +11,7 @@ pub use self::Node::*; use self::MapEntry::*; use self::collector::NodeCollector; -use self::def_collector::DefCollector; +pub use self::def_collector::{DefCollector, MacroInvocationData}; pub use self::definitions::{Definitions, DefKey, DefPath, DefPathData, DisambiguatedDefPathData, InlinedRootPath}; @@ -260,7 +260,7 @@ impl<'ast> Map<'ast> { EntryVariant(p, _) | EntryExpr(p, _) | EntryStmt(p, _) | - EntryTy(p, _) | + EntryTy(p, _) | EntryLocal(p, _) | EntryPat(p, _) | EntryBlock(p, _) | diff --git a/src/librustc/hir/mod.rs b/src/librustc/hir/mod.rs index 0cfdbae1a5..5f57ceac35 100644 --- a/src/librustc/hir/mod.rs +++ b/src/librustc/hir/mod.rs @@ -95,6 +95,7 @@ impl fmt::Debug for Lifetime { pub struct LifetimeDef { pub lifetime: Lifetime, pub bounds: HirVec, + pub pure_wrt_drop: bool, } /// A "Path" is essentially Rust's notion of a name; for instance: @@ -290,6 +291,7 @@ pub struct TyParam { pub bounds: TyParamBounds, pub default: Option>, pub span: Span, + pub pure_wrt_drop: bool, } /// Represents lifetimes and type parameters attached to a declaration @@ -328,6 +330,36 @@ impl Generics { } } +pub enum UnsafeGeneric { + Region(LifetimeDef, &'static str), + Type(TyParam, &'static str), +} + +impl UnsafeGeneric { + pub fn attr_name(&self) -> &'static str { + match *self { + UnsafeGeneric::Region(_, s) => s, + UnsafeGeneric::Type(_, s) => s, + } + } +} + +impl Generics { + pub fn carries_unsafe_attr(&self) -> Option { + for r in &self.lifetimes { + if r.pure_wrt_drop { + return Some(UnsafeGeneric::Region(r.clone(), "may_dangle")); + } + } + for t in &self.ty_params { + if t.pure_wrt_drop { + return Some(UnsafeGeneric::Type(t.clone(), "may_dangle")); + } + } + return None; + } +} + /// A `where` clause in a definition #[derive(Clone, PartialEq, Eq, RustcEncodable, RustcDecodable, Hash, Debug)] pub struct WhereClause { @@ -381,7 +413,6 @@ pub type CrateConfig = HirVec>; pub struct Crate { pub module: Mod, pub attrs: HirVec, - pub config: CrateConfig, pub span: Span, pub exported_macros: HirVec, @@ -426,8 +457,6 @@ pub struct MacroDef { pub id: NodeId, pub span: Span, pub imported_from: Option, - pub export: bool, - pub use_locally: bool, pub allow_internal_unstable: bool, pub body: HirVec, } @@ -478,7 +507,7 @@ impl Pat { PatKind::Box(ref s) | PatKind::Ref(ref s, _) => { s.walk_(it) } - PatKind::Vec(ref before, ref slice, ref after) => { + PatKind::Slice(ref before, ref slice, ref after) => { before.iter().all(|p| p.walk_(it)) && slice.iter().all(|p| p.walk_(it)) && after.iter().all(|p| p.walk_(it)) @@ -554,8 +583,8 @@ pub enum PatKind { /// A range pattern, e.g. `1...2` Range(P, P), /// `[a, b, ..i, y, z]` is represented as: - /// `PatKind::Vec(box [a, b], Some(i), box [y, z])` - Vec(HirVec>, Option>, HirVec>), + /// `PatKind::Slice(box [a, b], Some(i), box [y, z])` + Slice(HirVec>, Option>, HirVec>), } #[derive(Clone, PartialEq, Eq, RustcEncodable, RustcDecodable, Hash, Debug, Copy)] @@ -787,6 +816,7 @@ pub struct Field { pub name: Spanned, pub expr: P, pub span: Span, + pub is_shorthand: bool, } #[derive(Clone, PartialEq, Eq, RustcEncodable, RustcDecodable, Hash, Debug, Copy)] @@ -810,8 +840,8 @@ pub enum UnsafeSource { #[derive(Clone, PartialEq, Eq, RustcEncodable, RustcDecodable, Hash)] pub struct Expr { pub id: NodeId, - pub node: Expr_, pub span: Span, + pub node: Expr_, pub attrs: ThinVec, } @@ -826,7 +856,7 @@ pub enum Expr_ { /// A `box x` expression. ExprBox(P), /// An array (`[a, b, c, d]`) - ExprVec(HirVec>), + ExprArray(HirVec>), /// A function call /// /// The first field resolves to the function itself (usually an `ExprPath`), @@ -910,13 +940,13 @@ pub enum Expr_ { ExprRet(Option>), /// Inline assembly (from `asm!`), with its outputs and inputs. - ExprInlineAsm(InlineAsm, Vec>, Vec>), + ExprInlineAsm(P, HirVec>, HirVec>), /// A struct or struct-like variant literal expression. /// /// For example, `Foo {x: 1, y: 2}`, or /// `Foo {x: 1, .. base}`, where `base` is the `Option`. - ExprStruct(Path, HirVec, Option>), + ExprStruct(P, HirVec, Option>), /// An array literal constructed from one repeated element. /// @@ -1080,10 +1110,10 @@ pub struct BareFnTy { #[derive(Clone, PartialEq, Eq, RustcEncodable, RustcDecodable, Hash, Debug)] /// The different kinds of types recognized by the compiler pub enum Ty_ { - /// A variable length array (`[T]`) - TyVec(P), + /// A variable length slice (`[T]`) + TySlice(P), /// A fixed length array (`[T; n]`) - TyFixedLengthVec(P, P), + TyArray(P, P), /// A raw pointer (`*const T` or `*mut T`) TyPtr(MutTy), /// A reference (`&'a T` or `&'a mut T`) diff --git a/src/librustc/hir/pat_util.rs b/src/librustc/hir/pat_util.rs index dec41fdfc3..0deea94146 100644 --- a/src/librustc/hir/pat_util.rs +++ b/src/librustc/hir/pat_util.rs @@ -58,11 +58,11 @@ pub fn pat_is_refutable(dm: &DefMap, pat: &hir::Pat) -> bool { PatKind::Path(..) | PatKind::Struct(..) => { match dm.get(&pat.id).map(|d| d.full_def()) { - Some(Def::Variant(..)) => true, + Some(Def::Variant(..)) | Some(Def::VariantCtor(..)) => true, _ => false } } - PatKind::Vec(..) => true, + PatKind::Slice(..) => true, _ => false } } @@ -173,10 +173,9 @@ pub fn necessary_variants(dm: &DefMap, pat: &hir::Pat) -> Vec { PatKind::TupleStruct(..) | PatKind::Path(..) | PatKind::Struct(..) => { - match dm.get(&p.id) { - Some(&PathResolution { base_def: Def::Variant(id), .. }) => { - variants.push(id); - } + match dm.get(&p.id).map(|d| d.full_def()) { + Some(Def::Variant(id)) | + Some(Def::VariantCtor(id, ..)) => variants.push(id), _ => () } } diff --git a/src/librustc/hir/print.rs b/src/librustc/hir/print.rs index eebc8fa9e5..657c10bab1 100644 --- a/src/librustc/hir/print.rs +++ b/src/librustc/hir/print.rs @@ -486,7 +486,7 @@ impl<'a> State<'a> { self.maybe_print_comment(ty.span.lo)?; self.ibox(0)?; match ty.node { - hir::TyVec(ref ty) => { + hir::TySlice(ref ty) => { word(&mut self.s, "[")?; self.print_type(&ty)?; word(&mut self.s, "]")?; @@ -543,7 +543,7 @@ impl<'a> State<'a> { hir::TyImplTrait(ref bounds) => { self.print_bounds("impl ", &bounds[..])?; } - hir::TyFixedLengthVec(ref ty, ref v) => { + hir::TyArray(ref ty, ref v) => { word(&mut self.s, "[")?; self.print_type(&ty)?; word(&mut self.s, "; ")?; @@ -1229,8 +1229,10 @@ impl<'a> State<'a> { &fields[..], |s, field| { s.ibox(indent_unit)?; - s.print_name(field.name.node)?; - s.word_space(":")?; + if !field.is_shorthand { + s.print_name(field.name.node)?; + s.word_space(":")?; + } s.print_expr(&field.expr)?; s.end() }, @@ -1319,7 +1321,7 @@ impl<'a> State<'a> { self.word_space("box")?; self.print_expr(expr)?; } - hir::ExprVec(ref exprs) => { + hir::ExprArray(ref exprs) => { self.print_expr_vec(&exprs[..])?; } hir::ExprRepeat(ref element, ref count) => { @@ -1829,7 +1831,7 @@ impl<'a> State<'a> { word(&mut self.s, "...")?; self.print_expr(&end)?; } - PatKind::Vec(ref before, ref slice, ref after) => { + PatKind::Slice(ref before, ref slice, ref after) => { word(&mut self.s, "[")?; self.commasep(Inconsistent, &before[..], |s, p| s.print_pat(&p))?; if let Some(ref p) = *slice { diff --git a/src/librustc/infer/combine.rs b/src/librustc/infer/combine.rs index 5ce30484ed..fda08eba02 100644 --- a/src/librustc/infer/combine.rs +++ b/src/librustc/infer/combine.rs @@ -49,6 +49,7 @@ use ty::relate::{RelateResult, TypeRelation}; use traits::PredicateObligations; use syntax::ast; +use syntax::util::small_vector::SmallVector; use syntax_pos::Span; #[derive(Clone)] @@ -181,7 +182,9 @@ impl<'infcx, 'gcx, 'tcx> CombineFields<'infcx, 'gcx, 'tcx> { a_is_expected: bool) -> RelateResult<'tcx, ()> { - let mut stack = Vec::new(); + // We use SmallVector here instead of Vec because this code is hot and + // it's rare that the stack length exceeds 1. + let mut stack = SmallVector::zero(); stack.push((a_ty, dir, b_vid)); loop { // For each turn of the loop, we extract a tuple diff --git a/src/librustc/infer/error_reporting.rs b/src/librustc/infer/error_reporting.rs index 2792968d42..47c0bc5fd6 100644 --- a/src/librustc/infer/error_reporting.rs +++ b/src/librustc/infer/error_reporting.rs @@ -245,6 +245,7 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> { debug!("report_region_errors: {} errors after preprocessing", errors.len()); for error in errors { + debug!("report_region_errors: error = {:?}", error); match error.clone() { ConcreteFailure(origin, sub, sup) => { self.report_concrete_failure(origin, sub, sup).emit(); @@ -299,44 +300,64 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> { let mut bound_failures = Vec::new(); for error in errors { + // Check whether we can process this error into some other + // form; if not, fall through. match *error { ConcreteFailure(ref origin, sub, sup) => { debug!("processing ConcreteFailure"); - match free_regions_from_same_fn(self.tcx, sub, sup) { - Some(ref same_frs) => { - origins.push( - ProcessedErrorOrigin::ConcreteFailure( - origin.clone(), - sub, - sup)); - append_to_same_regions(&mut same_regions, same_frs); - } - _ => { - other_errors.push(error.clone()); - } + if let SubregionOrigin::CompareImplMethodObligation { .. } = *origin { + // When comparing an impl method against a + // trait method, it is not helpful to suggest + // changes to the impl method. This is + // because the impl method signature is being + // checked using the trait's environment, so + // usually the changes we suggest would + // actually have to be applied to the *trait* + // method (and it's not clear that the trait + // method is even under the user's control). + } else if let Some(same_frs) = free_regions_from_same_fn(self.tcx, sub, sup) { + origins.push( + ProcessedErrorOrigin::ConcreteFailure( + origin.clone(), + sub, + sup)); + append_to_same_regions(&mut same_regions, &same_frs); + continue; } } - SubSupConflict(ref var_origin, _, sub_r, _, sup_r) => { - debug!("processing SubSupConflict sub: {:?} sup: {:?}", sub_r, sup_r); - match free_regions_from_same_fn(self.tcx, sub_r, sup_r) { - Some(ref same_frs) => { - origins.push( - ProcessedErrorOrigin::VariableFailure( - var_origin.clone())); - append_to_same_regions(&mut same_regions, same_frs); + SubSupConflict(ref var_origin, ref sub_origin, sub, ref sup_origin, sup) => { + debug!("processing SubSupConflict sub: {:?} sup: {:?}", sub, sup); + match (sub_origin, sup_origin) { + (&SubregionOrigin::CompareImplMethodObligation { .. }, _) => { + // As above, when comparing an impl method + // against a trait method, it is not helpful + // to suggest changes to the impl method. } - None => { - other_errors.push(error.clone()); + (_, &SubregionOrigin::CompareImplMethodObligation { .. }) => { + // See above. + } + _ => { + if let Some(same_frs) = free_regions_from_same_fn(self.tcx, sub, sup) { + origins.push( + ProcessedErrorOrigin::VariableFailure( + var_origin.clone())); + append_to_same_regions(&mut same_regions, &same_frs); + continue; + } } } } GenericBoundFailure(ref origin, ref kind, region) => { bound_failures.push((origin.clone(), kind.clone(), region)); + continue; } ProcessedErrors(..) => { bug!("should not encounter a `ProcessedErrors` yet: {:?}", error) } } + + // No changes to this error. + other_errors.push(error.clone()); } // ok, let's pull together the errors, sorted in an order that @@ -457,7 +478,7 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> { } same_regions.push(SameRegions { scope_id: scope_id, - regions: vec!(sub_fr.bound_region, sup_fr.bound_region) + regions: vec![sub_fr.bound_region, sup_fr.bound_region] }) } } @@ -577,11 +598,16 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> { terr: &TypeError<'tcx>) -> DiagnosticBuilder<'tcx> { - // FIXME: do we want to use a different error code for each origin? - let mut diag = struct_span_err!( - self.tcx.sess, trace.origin.span(), E0308, - "{}", trace.origin.as_failure_str() - ); + let span = trace.origin.span(); + let failure_str = trace.origin.as_failure_str(); + let mut diag = match trace.origin { + TypeOrigin::IfExpressionWithNoElse(_) => { + struct_span_err!(self.tcx.sess, span, E0317, "{}", failure_str) + }, + _ => { + struct_span_err!(self.tcx.sess, span, E0308, "{}", failure_str) + }, + }; self.note_type_err(&mut diag, trace.origin, None, Some(trace.values), terr); diag } @@ -625,6 +651,19 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> { format!("the associated type `{}`", p), }; + if let SubregionOrigin::CompareImplMethodObligation { + span, item_name, impl_item_def_id, trait_item_def_id, lint_id + } = origin { + self.report_extra_impl_obligation(span, + item_name, + impl_item_def_id, + trait_item_def_id, + &format!("`{}: {}`", bound_kind, sub), + lint_id) + .emit(); + return; + } + let mut err = match *sub { ty::ReFree(ty::FreeRegion {bound_region: ty::BrNamed(..), ..}) => { // Does the required lifetime have a nice name we can print? @@ -942,6 +981,18 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> { ""); err } + infer::CompareImplMethodObligation { span, + item_name, + impl_item_def_id, + trait_item_def_id, + lint_id } => { + self.report_extra_impl_obligation(span, + item_name, + impl_item_def_id, + trait_item_def_id, + &format!("`{}: {}`", sup, sub), + lint_id) + } } } @@ -1226,16 +1277,17 @@ impl<'a, 'gcx, 'tcx> Rebuilder<'a, 'gcx, 'tcx> { lifetime: hir::Lifetime, region_names: &HashSet) -> hir::HirVec { - ty_params.iter().map(|ty_param| { - let bounds = self.rebuild_ty_param_bounds(ty_param.bounds.clone(), + ty_params.into_iter().map(|ty_param| { + let bounds = self.rebuild_ty_param_bounds(ty_param.bounds, lifetime, region_names); hir::TyParam { name: ty_param.name, id: ty_param.id, bounds: bounds, - default: ty_param.default.clone(), + default: ty_param.default, span: ty_param.span, + pure_wrt_drop: ty_param.pure_wrt_drop, } }).collect() } @@ -1294,8 +1346,11 @@ impl<'a, 'gcx, 'tcx> Rebuilder<'a, 'gcx, 'tcx> { -> hir::Generics { let mut lifetimes = Vec::new(); for lt in add { - lifetimes.push(hir::LifetimeDef { lifetime: *lt, - bounds: hir::HirVec::new() }); + lifetimes.push(hir::LifetimeDef { + lifetime: *lt, + bounds: hir::HirVec::new(), + pure_wrt_drop: false, + }); } for lt in &generics.lifetimes { if keep.contains(<.lifetime.name) || @@ -1350,7 +1405,7 @@ impl<'a, 'gcx, 'tcx> Rebuilder<'a, 'gcx, 'tcx> { region_names: &HashSet) -> P { let mut new_ty = P(ty.clone()); - let mut ty_queue = vec!(ty); + let mut ty_queue = vec![ty]; while !ty_queue.is_empty() { let cur_ty = ty_queue.remove(0); match cur_ty.node { @@ -1433,8 +1488,8 @@ impl<'a, 'gcx, 'tcx> Rebuilder<'a, 'gcx, 'tcx> { hir::TyPtr(ref mut_ty) => { ty_queue.push(&mut_ty.ty); } - hir::TyVec(ref ty) | - hir::TyFixedLengthVec(ref ty, _) => { + hir::TySlice(ref ty) | + hir::TyArray(ref ty, _) => { ty_queue.push(&ty); } hir::TyTup(ref tys) => ty_queue.extend(tys.iter().map(|ty| &**ty)), @@ -1469,9 +1524,9 @@ impl<'a, 'gcx, 'tcx> Rebuilder<'a, 'gcx, 'tcx> { ty: build_to(mut_ty.ty, to), }) } - hir::TyVec(ty) => hir::TyVec(build_to(ty, to)), - hir::TyFixedLengthVec(ty, e) => { - hir::TyFixedLengthVec(build_to(ty, to), e) + hir::TySlice(ty) => hir::TySlice(build_to(ty, to)), + hir::TyArray(ty, e) => { + hir::TyArray(build_to(ty, to), e) } hir::TyTup(tys) => { hir::TyTup(tys.into_iter().map(|ty| build_to(ty, to)).collect()) @@ -1783,6 +1838,11 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> { "...so that references are valid when the destructor \ runs"); } + infer::CompareImplMethodObligation { span, .. } => { + err.span_note( + span, + "...so that the definition in impl matches the definition from the trait"); + } } } } diff --git a/src/librustc/infer/freshen.rs b/src/librustc/infer/freshen.rs index eea12b7f19..828f9f32ba 100644 --- a/src/librustc/infer/freshen.rs +++ b/src/librustc/infer/freshen.rs @@ -61,9 +61,8 @@ impl<'a, 'gcx, 'tcx> TypeFreshener<'a, 'gcx, 'tcx> { -> Ty<'tcx> where F: FnOnce(u32) -> ty::InferTy, { - match opt_ty { - Some(ty) => { return ty.fold_with(self); } - None => { } + if let Some(ty) = opt_ty { + return ty.fold_with(self); } match self.freshen_map.entry(key) { diff --git a/src/librustc/infer/higher_ranked/mod.rs b/src/librustc/infer/higher_ranked/mod.rs index 7c02de05d2..25b899b3c5 100644 --- a/src/librustc/infer/higher_ranked/mod.rs +++ b/src/librustc/infer/higher_ranked/mod.rs @@ -749,13 +749,17 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> { pub fn plug_leaks(&self, skol_map: SkolemizationMap<'tcx>, snapshot: &CombinedSnapshot, - value: &T) -> T + value: T) -> T where T : TypeFoldable<'tcx> { debug!("plug_leaks(skol_map={:?}, value={:?})", skol_map, value); + if skol_map.is_empty() { + return value; + } + // Compute a mapping from the "taint set" of each skolemized // region back to the `ty::BoundRegion` that it originally // represented. Because `leak_check` passed, we know that @@ -775,7 +779,7 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> { // Remove any instantiated type variables from `value`; those can hide // references to regions from the `fold_regions` code below. - let value = self.resolve_type_vars_if_possible(value); + let value = self.resolve_type_vars_if_possible(&value); // Map any skolemization byproducts back to a late-bound // region. Put that late-bound region at whatever the outermost @@ -813,9 +817,6 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> { } }); - debug!("plug_leaks: result={:?}", - result); - self.pop_skolemized(skol_map, snapshot); debug!("plug_leaks: result={:?}", result); @@ -838,5 +839,9 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> { debug!("pop_skolemized({:?})", skol_map); let skol_regions: FnvHashSet<_> = skol_map.values().cloned().collect(); self.region_vars.pop_skolemized(&skol_regions, &snapshot.region_vars_snapshot); + if !skol_map.is_empty() { + self.projection_cache.borrow_mut().rollback_skolemized( + &snapshot.projection_cache_snapshot); + } } } diff --git a/src/librustc/infer/mod.rs b/src/librustc/infer/mod.rs index 4f74e765bd..21820ca071 100644 --- a/src/librustc/infer/mod.rs +++ b/src/librustc/infer/mod.rs @@ -25,7 +25,7 @@ use middle::mem_categorization as mc; use middle::mem_categorization::McResult; use middle::region::CodeExtent; use mir::tcx::LvalueTy; -use ty::subst::{Subst, Substs}; +use ty::subst::{Kind, Subst, Substs}; use ty::adjustment; use ty::{TyVid, IntVid, FloatVid}; use ty::{self, Ty, TyCtxt}; @@ -199,9 +199,6 @@ pub enum TypeOrigin { // Computing common supertype of an if expression with no else counter-part IfExpressionWithNoElse(Span), - // Computing common supertype in a range expression - RangeExpression(Span), - // `where a == b` EquatePredicate(Span), @@ -231,7 +228,6 @@ impl TypeOrigin { }, &TypeOrigin::IfExpression(_) => "if and else have incompatible types", &TypeOrigin::IfExpressionWithNoElse(_) => "if may be missing an else clause", - &TypeOrigin::RangeExpression(_) => "start and end of range have incompatible types", &TypeOrigin::EquatePredicate(_) => "equality predicate not satisfied", &TypeOrigin::MainFunctionType(_) => "main function has wrong type", &TypeOrigin::StartFunctionType(_) => "start function has wrong type", @@ -251,7 +247,6 @@ impl TypeOrigin { &TypeOrigin::MatchExpressionArm(..) => "match arms have compatible types", &TypeOrigin::IfExpression(_) => "if and else have compatible types", &TypeOrigin::IfExpressionWithNoElse(_) => "if missing an else returns ()", - &TypeOrigin::RangeExpression(_) => "start and end of range have compatible types", &TypeOrigin::EquatePredicate(_) => "equality where clause is satisfied", &TypeOrigin::MainFunctionType(_) => "`main` function has the correct type", &TypeOrigin::StartFunctionType(_) => "`start` function has the correct type", @@ -360,6 +355,19 @@ pub enum SubregionOrigin<'tcx> { // Region constraint arriving from destructor safety SafeDestructor(Span), + + // Comparing the signature and requirements of an impl method against + // the containing trait. + CompareImplMethodObligation { + span: Span, + item_name: ast::Name, + impl_item_def_id: DefId, + trait_item_def_id: DefId, + + // this is `Some(_)` if this error arises from the bug fix for + // #18937. This is a temporary measure. + lint_id: Option, + }, } /// Places that type/region parameters can appear. @@ -1061,7 +1069,10 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> { self.probe(|_| { let origin = TypeOrigin::Misc(syntax_pos::DUMMY_SP); let trace = TypeTrace::types(origin, true, a, b); - self.sub(true, trace, &a, &b).map(|_| ()) + self.sub(true, trace, &a, &b).map(|InferOk { obligations, .. }| { + // FIXME(#32730) propagate obligations + assert!(obligations.is_empty()); + }) }) } @@ -1152,16 +1163,18 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> { } pub fn region_outlives_predicate(&self, - span: Span, + cause: &traits::ObligationCause<'tcx>, predicate: &ty::PolyRegionOutlivesPredicate<'tcx>) -> UnitResult<'tcx> { self.commit_if_ok(|snapshot| { let (ty::OutlivesPredicate(r_a, r_b), skol_map) = self.skolemize_late_bound_regions(predicate, snapshot); - let origin = RelateRegionParamBound(span); + let origin = + SubregionOrigin::from_obligation_cause(cause, + || RelateRegionParamBound(cause.span)); self.sub_regions(origin, r_b, r_a); // `b : a` ==> `a <= b` - self.leak_check(false, span, &skol_map, snapshot)?; + self.leak_check(false, cause.span, &skol_map, snapshot)?; Ok(self.pop_skolemized(skol_map, snapshot)) }) } @@ -1221,7 +1234,7 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> { pub fn type_var_for_def(&self, span: Span, def: &ty::TypeParameterDef<'tcx>, - substs: &Substs<'tcx>) + substs: &[Kind<'tcx>]) -> Ty<'tcx> { let default = def.default.map(|default| { type_variable::Default { @@ -1256,26 +1269,6 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> { self.region_vars.new_bound(debruijn) } - /// Apply `adjustment` to the type of `expr` - pub fn adjust_expr_ty(&self, - expr: &hir::Expr, - adjustment: Option<&adjustment::AutoAdjustment<'tcx>>) - -> Ty<'tcx> - { - let raw_ty = self.expr_ty(expr); - let raw_ty = self.shallow_resolve(raw_ty); - let resolve_ty = |ty: Ty<'tcx>| self.resolve_type_vars_if_possible(&ty); - raw_ty.adjust(self.tcx, - expr.span, - expr.id, - adjustment, - |method_call| self.tables - .borrow() - .method_map - .get(&method_call) - .map(|method| resolve_ty(method.ty))) - } - /// True if errors have been reported since this infcx was /// created. This is sometimes used as a heuristic to skip /// reporting errors that often occur as a result of earlier @@ -1602,8 +1595,12 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> { // anyhow. We should make this typetrace stuff more // generic so we don't have to do anything quite this // terrible. - self.equate(true, TypeTrace::dummy(self.tcx), a, b) - }).map(|_| ()) + let trace = TypeTrace::dummy(self.tcx); + self.equate(true, trace, a, b).map(|InferOk { obligations, .. }| { + // FIXME(#32730) propagate obligations + assert!(obligations.is_empty()); + }) + }) } pub fn node_ty(&self, id: ast::NodeId) -> McResult> { @@ -1612,7 +1609,7 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> { } pub fn expr_ty_adjusted(&self, expr: &hir::Expr) -> McResult> { - let ty = self.adjust_expr_ty(expr, self.tables.borrow().adjustments.get(&expr.id)); + let ty = self.tables.borrow().expr_ty_adjusted(expr); self.resolve_type_vars_or_error(&ty) } @@ -1656,9 +1653,9 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> { .map(|method| method.def_id) } - pub fn adjustments(&self) -> Ref>> { + pub fn adjustments(&self) -> Ref>> { fn project_adjustments<'a, 'tcx>(tables: &'a ty::Tables<'tcx>) - -> &'a NodeMap> { + -> &'a NodeMap> { &tables.adjustments } @@ -1755,7 +1752,6 @@ impl TypeOrigin { TypeOrigin::MatchExpressionArm(match_span, ..) => match_span, TypeOrigin::IfExpression(span) => span, TypeOrigin::IfExpressionWithNoElse(span) => span, - TypeOrigin::RangeExpression(span) => span, TypeOrigin::EquatePredicate(span) => span, TypeOrigin::MainFunctionType(span) => span, TypeOrigin::StartFunctionType(span) => span, @@ -1792,6 +1788,32 @@ impl<'tcx> SubregionOrigin<'tcx> { AddrOf(a) => a, AutoBorrow(a) => a, SafeDestructor(a) => a, + CompareImplMethodObligation { span, .. } => span, + } + } + + pub fn from_obligation_cause(cause: &traits::ObligationCause<'tcx>, + default: F) + -> Self + where F: FnOnce() -> Self + { + match cause.code { + traits::ObligationCauseCode::ReferenceOutlivesReferent(ref_type) => + SubregionOrigin::ReferenceOutlivesReferent(ref_type, cause.span), + + traits::ObligationCauseCode::CompareImplMethodObligation { item_name, + impl_item_def_id, + trait_item_def_id, + lint_id } => + SubregionOrigin::CompareImplMethodObligation { + span: cause.span, + item_name: item_name, + impl_item_def_id: impl_item_def_id, + trait_item_def_id: trait_item_def_id, + lint_id: lint_id, + }, + + _ => default(), } } } diff --git a/src/librustc/infer/type_variable.rs b/src/librustc/infer/type_variable.rs index da9fd1cff2..3856ea420b 100644 --- a/src/librustc/infer/type_variable.rs +++ b/src/librustc/infer/type_variable.rs @@ -12,8 +12,9 @@ pub use self::RelationDir::*; use self::TypeVariableValue::*; use self::UndoEntry::*; use hir::def_id::{DefId}; -use ty::{self, Ty}; +use syntax::util::small_vector::SmallVector; use syntax_pos::Span; +use ty::{self, Ty}; use std::cmp::min; use std::marker::PhantomData; @@ -149,7 +150,7 @@ impl<'tcx> TypeVariableTable<'tcx> { &mut self, vid: ty::TyVid, ty: Ty<'tcx>, - stack: &mut Vec<(Ty<'tcx>, RelationDir, ty::TyVid)>) + stack: &mut SmallVector<(Ty<'tcx>, RelationDir, ty::TyVid)>) { debug_assert!(self.root_var(vid) == vid); let old_value = { diff --git a/src/librustc/lib.rs b/src/librustc/lib.rs index 25731df477..fa49e5c728 100644 --- a/src/librustc/lib.rs +++ b/src/librustc/lib.rs @@ -31,7 +31,7 @@ #![feature(conservative_impl_trait)] #![feature(const_fn)] #![feature(core_intrinsics)] -#![feature(dotdot_in_tuple_patterns)] +#![cfg_attr(stage0, feature(dotdot_in_tuple_patterns))] #![feature(enumset)] #![feature(libc)] #![feature(nonzero)] @@ -105,23 +105,12 @@ pub mod middle { pub mod weak_lang_items; } -pub mod mir { - mod cache; - pub mod repr; - pub mod tcx; - pub mod visit; - pub mod transform; - pub mod traversal; - pub mod mir_map; -} - +pub mod mir; pub mod session; pub mod traits; pub mod ty; pub mod util { - pub use rustc_back::sha2; - pub mod common; pub mod ppaux; pub mod nodemap; diff --git a/src/librustc/lint/builtin.rs b/src/librustc/lint/builtin.rs index d378772e65..82a46f7640 100644 --- a/src/librustc/lint/builtin.rs +++ b/src/librustc/lint/builtin.rs @@ -120,35 +120,29 @@ declare_lint! { declare_lint! { pub INACCESSIBLE_EXTERN_CRATE, - Warn, + Deny, "use of inaccessible extern crate erroneously allowed" } declare_lint! { pub INVALID_TYPE_PARAM_DEFAULT, - Warn, + Deny, "type parameter default erroneously allowed in invalid location" } declare_lint! { pub ILLEGAL_FLOATING_POINT_CONSTANT_PATTERN, - Warn, + Deny, "floating-point constants cannot be used in patterns" } declare_lint! { pub ILLEGAL_STRUCT_OR_ENUM_CONSTANT_PATTERN, - Warn, + Deny, "constants of struct or enum type can only be used in a pattern if \ the struct or enum has `#[derive(PartialEq, Eq)]`" } -declare_lint! { - pub MATCH_OF_UNIT_VARIANT_VIA_PAREN_DOTDOT, - Deny, - "unit struct or enum variant erroneously allowed to match via path::ident(..)" -} - declare_lint! { pub RAW_POINTER_DERIVE, Warn, @@ -170,7 +164,7 @@ declare_lint! { declare_lint! { pub OVERLAPPING_INHERENT_IMPLS, - Warn, + Deny, "two overlapping inherent impls define an item with the same name were erroneously allowed" } @@ -182,13 +176,13 @@ declare_lint! { declare_lint! { pub SUPER_OR_SELF_IN_GLOBAL_PATH, - Warn, + Deny, "detects super or self keywords at the beginning of global path" } declare_lint! { pub LIFETIME_UNDERSCORE, - Warn, + Deny, "lifetimes or labels named `'_` were erroneously allowed" } @@ -198,6 +192,18 @@ declare_lint! { "safe access to extern statics was erroneously allowed" } +declare_lint! { + pub PATTERNS_IN_FNS_WITHOUT_BODY, + Warn, + "patterns in functions without body were erroneously allowed" +} + +declare_lint! { + pub EXTRA_REQUIREMENT_IN_IMPL, + Warn, + "detects extra requirements in impls that were erroneously allowed" +} + /// Does nothing as a lint pass, but registers some `Lint`s /// which are used by other parts of the compiler. #[derive(Copy, Clone)] @@ -226,7 +232,6 @@ impl LintPass for HardwiredLints { INVALID_TYPE_PARAM_DEFAULT, ILLEGAL_FLOATING_POINT_CONSTANT_PATTERN, ILLEGAL_STRUCT_OR_ENUM_CONSTANT_PATTERN, - MATCH_OF_UNIT_VARIANT_VIA_PAREN_DOTDOT, CONST_ERR, RAW_POINTER_DERIVE, TRANSMUTE_FROM_FN_ITEM_TYPES, @@ -235,7 +240,9 @@ impl LintPass for HardwiredLints { SUPER_OR_SELF_IN_GLOBAL_PATH, HR_LIFETIME_IN_ASSOC_TYPE, LIFETIME_UNDERSCORE, - SAFE_EXTERN_STATICS + SAFE_EXTERN_STATICS, + PATTERNS_IN_FNS_WITHOUT_BODY, + EXTRA_REQUIREMENT_IN_IMPL ) } } diff --git a/src/librustc/lint/context.rs b/src/librustc/lint/context.rs index 81d3d440b5..f08aa2eb49 100644 --- a/src/librustc/lint/context.rs +++ b/src/librustc/lint/context.rs @@ -38,11 +38,12 @@ use util::nodemap::FnvHashMap; use std::cmp; use std::default::Default as StdDefault; use std::mem; +use std::fmt; use syntax::attr; use syntax::parse::token::InternedString; use syntax::ast; -use syntax_pos::Span; -use errors::DiagnosticBuilder; +use syntax_pos::{MultiSpan, Span}; +use errors::{self, Diagnostic, DiagnosticBuilder}; use hir; use hir::intravisit as hir_visit; use syntax::visit as ast_visit; @@ -80,6 +81,46 @@ pub struct LintStore { lint_cap: Option, } +/// When you call `add_lint` on the session, you wind up storing one +/// of these, which records a "potential lint" at a particular point. +#[derive(PartialEq)] +pub struct EarlyLint { + /// what lint is this? (e.g., `dead_code`) + pub id: LintId, + + /// the main message + pub diagnostic: Diagnostic, +} + +impl fmt::Debug for EarlyLint { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + f.debug_struct("EarlyLint") + .field("id", &self.id) + .field("span", &self.diagnostic.span) + .field("diagnostic", &self.diagnostic) + .finish() + } +} + +pub trait IntoEarlyLint { + fn into_early_lint(self, id: LintId) -> EarlyLint; +} + +impl<'a> IntoEarlyLint for (Span, &'a str) { + fn into_early_lint(self, id: LintId) -> EarlyLint { + let (span, msg) = self; + let mut diagnostic = Diagnostic::new(errors::Level::Warning, msg); + diagnostic.set_span(span); + EarlyLint { id: id, diagnostic: diagnostic } + } +} + +impl IntoEarlyLint for Diagnostic { + fn into_early_lint(self, id: LintId) -> EarlyLint { + EarlyLint { id: id, diagnostic: self } + } +} + /// Extra information for a future incompatibility lint. See the call /// to `register_future_incompatible` in `librustc_lint/lib.rs` for /// guidelines. @@ -127,9 +168,9 @@ impl LintStore { pub fn new() -> LintStore { LintStore { - lints: vec!(), - early_passes: Some(vec!()), - late_passes: Some(vec!()), + lints: vec![], + early_passes: Some(vec![]), + late_passes: Some(vec![]), by_name: FnvHashMap(), levels: FnvHashMap(), future_incompatible: FnvHashMap(), @@ -345,7 +386,7 @@ macro_rules! run_lints { ($cx:expr, $f:ident, $ps:ident, $($args:expr),*) => ({ // See also the hir version just below. pub fn gather_attrs(attrs: &[ast::Attribute]) -> Vec> { - let mut out = vec!(); + let mut out = vec![]; for attr in attrs { let r = gather_attr(attr); out.extend(r.into_iter()); @@ -355,7 +396,7 @@ pub fn gather_attrs(attrs: &[ast::Attribute]) pub fn gather_attr(attr: &ast::Attribute) -> Vec> { - let mut out = vec!(); + let mut out = vec![]; let level = match Level::from_str(&attr.name()) { None => return out, @@ -388,22 +429,24 @@ pub fn gather_attr(attr: &ast::Attribute) /// in trans that run after the main lint pass is finished. Most /// lints elsewhere in the compiler should call /// `Session::add_lint()` instead. -pub fn raw_emit_lint(sess: &Session, - lints: &LintStore, - lint: &'static Lint, - lvlsrc: LevelSource, - span: Option, - msg: &str) { +pub fn raw_emit_lint>(sess: &Session, + lints: &LintStore, + lint: &'static Lint, + lvlsrc: LevelSource, + span: Option, + msg: &str) { raw_struct_lint(sess, lints, lint, lvlsrc, span, msg).emit(); } -pub fn raw_struct_lint<'a>(sess: &'a Session, - lints: &LintStore, - lint: &'static Lint, - lvlsrc: LevelSource, - span: Option, - msg: &str) - -> DiagnosticBuilder<'a> { +pub fn raw_struct_lint<'a, S>(sess: &'a Session, + lints: &LintStore, + lint: &'static Lint, + lvlsrc: LevelSource, + span: Option, + msg: &str) + -> DiagnosticBuilder<'a> + where S: Into +{ let (mut level, source) = lvlsrc; if level == Allow { return sess.diagnostic().struct_dummy(); @@ -452,8 +495,7 @@ pub fn raw_struct_lint<'a>(sess: &'a Session, } if let Some(span) = def { - let explanation = "lint level defined here"; - err.span_note(span, &explanation); + sess.diag_span_note_once(&mut err, lint, span, "lint level defined here"); } err @@ -497,11 +539,11 @@ pub trait LintContext: Sized { raw_emit_lint(&self.sess(), self.lints(), lint, (level, src), span, msg); } - fn lookup(&self, - lint: &'static Lint, - span: Option, - msg: &str) - -> DiagnosticBuilder { + fn lookup>(&self, + lint: &'static Lint, + span: Option, + msg: &str) + -> DiagnosticBuilder { let (level, src) = match self.level_src(lint) { None => return self.sess().diagnostic().struct_dummy(), Some(pair) => pair, @@ -515,11 +557,20 @@ pub trait LintContext: Sized { self.lookup_and_emit(lint, Some(span), msg); } - fn struct_span_lint(&self, - lint: &'static Lint, - span: Span, - msg: &str) - -> DiagnosticBuilder { + fn early_lint(&self, early_lint: EarlyLint) { + let span = early_lint.diagnostic.span.primary_span().expect("early lint w/o primary span"); + let mut err = self.struct_span_lint(early_lint.id.lint, + span, + &early_lint.diagnostic.message); + err.copy_details_not_message(&early_lint.diagnostic); + err.emit(); + } + + fn struct_span_lint>(&self, + lint: &'static Lint, + span: S, + msg: &str) + -> DiagnosticBuilder { self.lookup(lint, Some(span), msg) } @@ -1066,8 +1117,8 @@ impl<'a, 'b, 'tcx, 'v> hir_visit::Visitor<'v> for IdVisitor<'a, 'b, 'tcx> { fn visit_id(&mut self, id: ast::NodeId) { if let Some(lints) = self.cx.sess().lints.borrow_mut().remove(&id) { debug!("LateContext::visit_id: id={:?} lints={:?}", id, lints); - for (lint_id, span, msg) in lints { - self.cx.span_lint(lint_id.lint, span, &msg[..]) + for early_lint in lints { + self.cx.early_lint(early_lint); } } } @@ -1212,10 +1263,10 @@ pub fn check_crate<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, // If we missed any lints added to the session, then there's a bug somewhere // in the iteration code. for (id, v) in tcx.sess.lints.borrow().iter() { - for &(lint, span, ref msg) in v { - span_bug!(span, - "unprocessed lint {} at {}: {}", - lint.to_string(), tcx.map.node_to_string(*id), *msg) + for early_lint in v { + span_bug!(early_lint.diagnostic.span.clone(), + "unprocessed lint {:?} at {}", + early_lint, tcx.map.node_to_string(*id)); } } @@ -1230,8 +1281,8 @@ pub fn check_ast_crate(sess: &Session, krate: &ast::Crate) { cx.with_lint_attrs(&krate.attrs, |cx| { // Lints may be assigned to the whole crate. if let Some(lints) = cx.sess.lints.borrow_mut().remove(&ast::CRATE_NODE_ID) { - for (lint_id, span, msg) in lints { - cx.span_lint(lint_id.lint, span, &msg[..]) + for early_lint in lints { + cx.early_lint(early_lint); } } @@ -1250,8 +1301,8 @@ pub fn check_ast_crate(sess: &Session, krate: &ast::Crate) { // If we missed any lints added to the session, then there's a bug somewhere // in the iteration code. for (_, v) in sess.lints.borrow().iter() { - for &(lint, span, ref msg) in v { - span_bug!(span, "unprocessed lint {}: {}", lint.to_string(), *msg) + for early_lint in v { + span_bug!(early_lint.diagnostic.span.clone(), "unprocessed lint {:?}", early_lint); } } } diff --git a/src/librustc/lint/mod.rs b/src/librustc/lint/mod.rs index 0938086b00..34e0ce7da1 100644 --- a/src/librustc/lint/mod.rs +++ b/src/librustc/lint/mod.rs @@ -41,7 +41,7 @@ use hir; pub use lint::context::{LateContext, EarlyContext, LintContext, LintStore, raw_emit_lint, check_crate, check_ast_crate, gather_attrs, - raw_struct_lint, FutureIncompatibleInfo}; + raw_struct_lint, FutureIncompatibleInfo, EarlyLint, IntoEarlyLint}; /// Specification of a single lint. #[derive(Copy, Clone, Debug)] @@ -314,5 +314,4 @@ pub enum LintSource { pub type LevelSource = (Level, LintSource); pub mod builtin; - mod context; diff --git a/src/librustc/middle/cstore.rs b/src/librustc/middle/cstore.rs index 107cf9b6ca..59a5147ed1 100644 --- a/src/librustc/middle/cstore.rs +++ b/src/librustc/middle/cstore.rs @@ -29,23 +29,21 @@ use hir::map::definitions::{Definitions, DefKey}; use hir::svh::Svh; use middle::lang_items; use ty::{self, Ty, TyCtxt}; -use mir::repr::Mir; -use mir::mir_map::MirMap; +use mir::Mir; use session::Session; -use session::config::PanicStrategy; use session::search_paths::PathKind; use util::nodemap::{NodeSet, DefIdMap}; use std::path::PathBuf; -use std::rc::Rc; use syntax::ast; use syntax::attr; -use syntax::ext::base::MultiItemModifier; +use syntax::ext::base::SyntaxExtension; use syntax::ptr::P; use syntax::parse::token::InternedString; use syntax_pos::Span; use rustc_back::target::Target; use hir; use hir::intravisit::Visitor; +use rustc_back::PanicStrategy; pub use self::NativeLibraryKind::{NativeStatic, NativeFramework, NativeUnknown}; @@ -166,7 +164,6 @@ pub trait CrateStore<'tcx> { fn is_const_fn(&self, did: DefId) -> bool; fn is_defaulted_trait(&self, did: DefId) -> bool; fn is_default_impl(&self, impl_did: DefId) -> bool; - fn is_extern_item<'a>(&self, tcx: TyCtxt<'a, 'tcx, 'tcx>, did: DefId) -> bool; fn is_foreign_item(&self, did: DefId) -> bool; fn is_statically_included_foreign_item(&self, id: ast::NodeId) -> bool; @@ -201,8 +198,6 @@ pub trait CrateStore<'tcx> { -> Option; fn def_key(&self, def: DefId) -> hir_map::DefKey; fn relative_def_path(&self, def: DefId) -> Option; - fn variant_kind(&self, def_id: DefId) -> Option; - fn struct_ctor_def_id(&self, struct_def_id: DefId) -> Option; fn struct_field_names(&self, def: DefId) -> Vec; fn item_children(&self, did: DefId) -> Vec; @@ -212,8 +207,7 @@ pub trait CrateStore<'tcx> { fn local_node_for_inlined_defid(&'tcx self, def_id: DefId) -> Option; fn defid_for_inlined_node(&'tcx self, node_id: ast::NodeId) -> Option; - fn maybe_get_item_mir<'a>(&self, tcx: TyCtxt<'a, 'tcx, 'tcx>, def: DefId) - -> Option>; + fn get_item_mir<'a>(&self, tcx: TyCtxt<'a, 'tcx, 'tcx>, def: DefId) -> Mir<'tcx>; fn is_item_mir_available(&self, def: DefId) -> bool; // This is basically a 1-based range of ints, which is a little @@ -231,8 +225,7 @@ pub trait CrateStore<'tcx> { fn encode_metadata<'a>(&self, tcx: TyCtxt<'a, 'tcx, 'tcx>, reexports: &def::ExportMap, link_meta: &LinkMeta, - reachable: &NodeSet, - mir_map: &MirMap<'tcx>) -> Vec; + reachable: &NodeSet) -> Vec; fn metadata_encoding_version(&self) -> &[u8]; } @@ -337,8 +330,6 @@ impl<'tcx> CrateStore<'tcx> for DummyCrateStore { fn is_const_fn(&self, did: DefId) -> bool { bug!("is_const_fn") } fn is_defaulted_trait(&self, did: DefId) -> bool { bug!("is_defaulted_trait") } fn is_default_impl(&self, impl_did: DefId) -> bool { bug!("is_default_impl") } - fn is_extern_item<'a>(&self, tcx: TyCtxt<'a, 'tcx, 'tcx>, did: DefId) -> bool - { bug!("is_extern_item") } fn is_foreign_item(&self, did: DefId) -> bool { bug!("is_foreign_item") } fn is_statically_included_foreign_item(&self, id: ast::NodeId) -> bool { false } @@ -378,9 +369,6 @@ impl<'tcx> CrateStore<'tcx> for DummyCrateStore { fn relative_def_path(&self, def: DefId) -> Option { bug!("relative_def_path") } - fn variant_kind(&self, def_id: DefId) -> Option { bug!("variant_kind") } - fn struct_ctor_def_id(&self, struct_def_id: DefId) -> Option - { bug!("struct_ctor_def_id") } fn struct_field_names(&self, def: DefId) -> Vec { bug!("struct_field_names") } fn item_children(&self, did: DefId) -> Vec { bug!("item_children") } @@ -396,8 +384,8 @@ impl<'tcx> CrateStore<'tcx> for DummyCrateStore { bug!("defid_for_inlined_node") } - fn maybe_get_item_mir<'a>(&self, tcx: TyCtxt<'a, 'tcx, 'tcx>, def: DefId) - -> Option> { bug!("maybe_get_item_mir") } + fn get_item_mir<'a>(&self, tcx: TyCtxt<'a, 'tcx, 'tcx>, def: DefId) + -> Mir<'tcx> { bug!("get_item_mir") } fn is_item_mir_available(&self, def: DefId) -> bool { bug!("is_item_mir_available") } @@ -418,18 +406,26 @@ impl<'tcx> CrateStore<'tcx> for DummyCrateStore { fn encode_metadata<'a>(&self, tcx: TyCtxt<'a, 'tcx, 'tcx>, reexports: &def::ExportMap, link_meta: &LinkMeta, - reachable: &NodeSet, - mir_map: &MirMap<'tcx>) -> Vec { vec![] } + reachable: &NodeSet) -> Vec { vec![] } fn metadata_encoding_version(&self) -> &[u8] { bug!("metadata_encoding_version") } } -pub enum LoadedMacro { - Def(ast::MacroDef), - CustomDerive(String, Rc), +pub enum LoadedMacros { + MacroRules(Vec), + ProcMacros(Vec<(ast::Name, SyntaxExtension)>), +} + +impl LoadedMacros { + pub fn is_proc_macros(&self) -> bool { + match *self { + LoadedMacros::ProcMacros(_) => true, + _ => false, + } + } } pub trait CrateLoader { - fn load_macros(&mut self, extern_crate: &ast::Item, allows_macros: bool) -> Vec; - fn process_item(&mut self, item: &ast::Item, defs: &Definitions); + fn process_item(&mut self, item: &ast::Item, defs: &Definitions, load_macros: bool) + -> Option; fn postprocess(&mut self, krate: &ast::Crate); } diff --git a/src/librustc/middle/dead.rs b/src/librustc/middle/dead.rs index 30a0c6a9dc..4212b1fb05 100644 --- a/src/librustc/middle/dead.rs +++ b/src/librustc/middle/dead.rs @@ -92,7 +92,7 @@ impl<'a, 'tcx> MarkSymbolVisitor<'a, 'tcx> { match def { Def::AssociatedTy(..) | Def::Method(_) | Def::AssociatedConst(_) if self.tcx.trait_of_item(def.def_id()).is_some() => { - if let Some(substs) = self.tcx.tables.borrow().item_substs.get(&id) { + if let Some(substs) = self.tcx.tables().item_substs.get(&id) { if let ty::TyAdt(tyid, _) = substs.substs.type_at(0).sty { self.check_def_id(tyid.did); } @@ -106,9 +106,8 @@ impl<'a, 'tcx> MarkSymbolVisitor<'a, 'tcx> { self.check_def_id(def.def_id()); } _ if self.ignore_non_const_paths => (), - Def::PrimTy(_) => (), - Def::SelfTy(..) => (), - Def::Variant(variant_id) => { + Def::PrimTy(..) | Def::SelfTy(..) => (), + Def::Variant(variant_id) | Def::VariantCtor(variant_id, ..) => { if let Some(enum_id) = self.tcx.parent_def_id(variant_id) { self.check_def_id(enum_id); } @@ -124,12 +123,12 @@ impl<'a, 'tcx> MarkSymbolVisitor<'a, 'tcx> { fn lookup_and_handle_method(&mut self, id: ast::NodeId) { let method_call = ty::MethodCall::expr(id); - let method = self.tcx.tables.borrow().method_map[&method_call]; + let method = self.tcx.tables().method_map[&method_call]; self.check_def_id(method.def_id); } fn handle_field_access(&mut self, lhs: &hir::Expr, name: ast::Name) { - match self.tcx.expr_ty_adjusted(lhs).sty { + match self.tcx.tables().expr_ty_adjusted(lhs).sty { ty::TyAdt(def, _) => { self.insert_def_id(def.struct_variant().field_named(name).did); } @@ -138,7 +137,7 @@ impl<'a, 'tcx> MarkSymbolVisitor<'a, 'tcx> { } fn handle_tup_field_access(&mut self, lhs: &hir::Expr, idx: usize) { - match self.tcx.expr_ty_adjusted(lhs).sty { + match self.tcx.tables().expr_ty_adjusted(lhs).sty { ty::TyAdt(def, _) => { self.insert_def_id(def.struct_variant().fields[idx].did); } @@ -149,7 +148,7 @@ impl<'a, 'tcx> MarkSymbolVisitor<'a, 'tcx> { fn handle_field_pattern_match(&mut self, lhs: &hir::Pat, pats: &[codemap::Spanned]) { - let variant = match self.tcx.node_id_to_type(lhs.id).sty { + let variant = match self.tcx.tables().node_id_to_type(lhs.id).sty { ty::TyAdt(adt, _) => { adt.variant_of_def(self.tcx.expect_def(lhs.id)) } @@ -434,7 +433,7 @@ impl<'a, 'tcx> DeadVisitor<'a, 'tcx> { } fn should_warn_about_field(&mut self, field: &hir::StructField) -> bool { - let field_type = self.tcx.node_id_to_type(field.id); + let field_type = self.tcx.tables().node_id_to_type(field.id); let is_marker_field = match field_type.ty_to_def_id() { Some(def_id) => self.tcx.lang_items.items().iter().any(|item| *item == Some(def_id)), _ => false diff --git a/src/librustc/middle/dependency_format.rs b/src/librustc/middle/dependency_format.rs index c6908e11ed..656d3146fe 100644 --- a/src/librustc/middle/dependency_format.rs +++ b/src/librustc/middle/dependency_format.rs @@ -64,9 +64,10 @@ use hir::def_id::CrateNum; use session; -use session::config::{self, PanicStrategy}; +use session::config; use middle::cstore::LinkagePreference::{self, RequireStatic, RequireDynamic}; use util::nodemap::FnvHashMap; +use rustc_back::PanicStrategy; /// A list of dependencies for a certain crate type. /// @@ -140,12 +141,12 @@ fn calculate_type(sess: &session::Session, } // Everything else falls through below. This will happen either with the - // `-C prefer-dynamic` or because we're a rustc-macro crate. Note that - // rustc-macro crates are required to be dylibs, and they're currently + // `-C prefer-dynamic` or because we're a proc-macro crate. Note that + // proc-macro crates are required to be dylibs, and they're currently // required to link to libsyntax as well. config::CrateTypeExecutable | config::CrateTypeDylib | - config::CrateTypeRustcMacro => {}, + config::CrateTypeProcMacro => {}, } let mut formats = FnvHashMap(); @@ -357,7 +358,7 @@ fn verify_ok(sess: &session::Session, list: &[Linkage]) { // only one, but we perform validation here that all the panic strategy // compilation modes for the whole DAG are valid. if let Some((cnum, found_strategy)) = panic_runtime { - let desired_strategy = sess.opts.cg.panic.clone(); + let desired_strategy = sess.panic_strategy(); // First up, validate that our selected panic runtime is indeed exactly // our same strategy. diff --git a/src/librustc/middle/effect.rs b/src/librustc/middle/effect.rs index 2a75b6620f..8ca3c75eaa 100644 --- a/src/librustc/middle/effect.rs +++ b/src/librustc/middle/effect.rs @@ -159,7 +159,7 @@ impl<'a, 'tcx, 'v> Visitor<'v> for EffectCheckVisitor<'a, 'tcx> { match expr.node { hir::ExprMethodCall(..) => { let method_call = MethodCall::expr(expr.id); - let base_type = self.tcx.tables.borrow().method_map[&method_call].ty; + let base_type = self.tcx.tables().method_map[&method_call].ty; debug!("effect: method call case, base type is {:?}", base_type); if type_is_unsafe_function(base_type) { @@ -168,7 +168,7 @@ impl<'a, 'tcx, 'v> Visitor<'v> for EffectCheckVisitor<'a, 'tcx> { } } hir::ExprCall(ref base, _) => { - let base_type = self.tcx.expr_ty_adjusted(base); + let base_type = self.tcx.tables().expr_ty_adjusted(base); debug!("effect: call case, base type is {:?}", base_type); if type_is_unsafe_function(base_type) { @@ -176,7 +176,7 @@ impl<'a, 'tcx, 'v> Visitor<'v> for EffectCheckVisitor<'a, 'tcx> { } } hir::ExprUnary(hir::UnDeref, ref base) => { - let base_type = self.tcx.expr_ty_adjusted(base); + let base_type = self.tcx.tables().expr_ty_adjusted(base); debug!("effect: unary case, base type is {:?}", base_type); if let ty::TyRawPtr(_) = base_type.sty { @@ -200,7 +200,7 @@ impl<'a, 'tcx, 'v> Visitor<'v> for EffectCheckVisitor<'a, 'tcx> { } } hir::ExprField(ref base_expr, field) => { - if let ty::TyAdt(adt, ..) = self.tcx.expr_ty_adjusted(base_expr).sty { + if let ty::TyAdt(adt, ..) = self.tcx.tables().expr_ty_adjusted(base_expr).sty { if adt.is_union() { self.require_unsafe(field.span, "access to union field"); } @@ -214,7 +214,7 @@ impl<'a, 'tcx, 'v> Visitor<'v> for EffectCheckVisitor<'a, 'tcx> { fn visit_pat(&mut self, pat: &hir::Pat) { if let PatKind::Struct(_, ref fields, _) = pat.node { - if let ty::TyAdt(adt, ..) = self.tcx.pat_ty(pat).sty { + if let ty::TyAdt(adt, ..) = self.tcx.tables().pat_ty(pat).sty { if adt.is_union() { for field in fields { self.require_unsafe(field.span, "matching on union field"); diff --git a/src/librustc/middle/expr_use_visitor.rs b/src/librustc/middle/expr_use_visitor.rs index 5b5c3da8f0..0543d1303a 100644 --- a/src/librustc/middle/expr_use_visitor.rs +++ b/src/librustc/middle/expr_use_visitor.rs @@ -442,7 +442,7 @@ impl<'a, 'gcx, 'tcx> ExprUseVisitor<'a, 'gcx, 'tcx> { } } - hir::ExprVec(ref exprs) => { + hir::ExprArray(ref exprs) => { self.consume_exprs(exprs); } @@ -720,11 +720,11 @@ impl<'a, 'gcx, 'tcx> ExprUseVisitor<'a, 'gcx, 'tcx> { //NOTE(@jroesch): mixed RefCell borrow causes crash let adj = infcx.adjustments().get(&expr.id).map(|x| x.clone()); if let Some(adjustment) = adj { - match adjustment { - adjustment::AdjustNeverToAny(..) | - adjustment::AdjustReifyFnPointer | - adjustment::AdjustUnsafeFnPointer | - adjustment::AdjustMutToConstPointer => { + match adjustment.kind { + adjustment::Adjust::NeverToAny | + adjustment::Adjust::ReifyFnPointer | + adjustment::Adjust::UnsafeFnPointer | + adjustment::Adjust::MutToConstPointer => { // Creating a closure/fn-pointer or unsizing consumes // the input and stores it into the resulting rvalue. debug!("walk_adjustment: trivial adjustment"); @@ -732,8 +732,21 @@ impl<'a, 'gcx, 'tcx> ExprUseVisitor<'a, 'gcx, 'tcx> { return_if_err!(self.mc.cat_expr_unadjusted(expr)); self.delegate_consume(expr.id, expr.span, cmt_unadjusted); } - adjustment::AdjustDerefRef(ref adj) => { - self.walk_autoderefref(expr, adj); + adjustment::Adjust::DerefRef { autoderefs, autoref, unsize } => { + debug!("walk_adjustment expr={:?} adj={:?}", expr, adjustment); + + self.walk_autoderefs(expr, autoderefs); + + let cmt_derefd = + return_if_err!(self.mc.cat_expr_autoderefd(expr, autoderefs)); + + let cmt_refd = + self.walk_autoref(expr, cmt_derefd, autoref); + + if unsize { + // Unsizing consumes the thin pointer and produces a fat one. + self.delegate_consume(expr.id, expr.span, cmt_refd); + } } } } @@ -770,28 +783,6 @@ impl<'a, 'gcx, 'tcx> ExprUseVisitor<'a, 'gcx, 'tcx> { } } - fn walk_autoderefref(&mut self, - expr: &hir::Expr, - adj: &adjustment::AutoDerefRef<'tcx>) { - debug!("walk_autoderefref expr={:?} adj={:?}", - expr, - adj); - - 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 @@ -803,7 +794,7 @@ impl<'a, 'gcx, 'tcx> ExprUseVisitor<'a, 'gcx, 'tcx> { fn walk_autoref(&mut self, expr: &hir::Expr, cmt_base: mc::cmt<'tcx>, - opt_autoref: Option>) + opt_autoref: Option>) -> mc::cmt<'tcx> { debug!("walk_autoref(expr.id={} cmt_derefd={:?} opt_autoref={:?})", @@ -822,7 +813,7 @@ impl<'a, 'gcx, 'tcx> ExprUseVisitor<'a, 'gcx, 'tcx> { }; match *autoref { - adjustment::AutoPtr(r, m) => { + adjustment::AutoBorrow::Ref(r, m) => { self.delegate.borrow(expr.id, expr.span, cmt_base, @@ -831,7 +822,7 @@ impl<'a, 'gcx, 'tcx> ExprUseVisitor<'a, 'gcx, 'tcx> { AutoRef); } - adjustment::AutoUnsafe(m) => { + adjustment::AutoBorrow::RawPtr(m) => { debug!("walk_autoref: expr.id={} cmt_base={:?}", expr.id, cmt_base); @@ -1003,7 +994,8 @@ impl<'a, 'gcx, 'tcx> ExprUseVisitor<'a, 'gcx, 'tcx> { // the leaves of the pattern tree structure. return_if_err!(mc.cat_pattern(cmt_discr, pat, |mc, cmt_pat, pat| { match tcx.expect_def_or_none(pat.id) { - Some(Def::Variant(variant_did)) => { + Some(Def::Variant(variant_did)) | + Some(Def::VariantCtor(variant_did, ..)) => { let enum_did = tcx.parent_def_id(variant_did).unwrap(); let downcast_cmt = if tcx.lookup_adt_def(enum_did).is_univariant() { cmt_pat @@ -1015,12 +1007,14 @@ impl<'a, 'gcx, 'tcx> ExprUseVisitor<'a, 'gcx, 'tcx> { debug!("variant downcast_cmt={:?} pat={:?}", downcast_cmt, pat); delegate.matched_pat(pat, downcast_cmt, match_mode); } - Some(Def::Struct(..)) | Some(Def::Union(..)) | - Some(Def::TyAlias(..)) | Some(Def::AssociatedTy(..)) => { + Some(Def::Struct(..)) | Some(Def::StructCtor(..)) | Some(Def::Union(..)) | + Some(Def::TyAlias(..)) | Some(Def::AssociatedTy(..)) | Some(Def::SelfTy(..)) => { debug!("struct cmt_pat={:?} pat={:?}", cmt_pat, pat); delegate.matched_pat(pat, cmt_pat, match_mode); } - _ => {} + None | Some(Def::Local(..)) | + Some(Def::Const(..)) | Some(Def::AssociatedConst(..)) => {} + def => bug!("unexpected definition: {:?}", def) } })); } diff --git a/src/librustc/middle/intrinsicck.rs b/src/librustc/middle/intrinsicck.rs index 1acd0fb0f7..57503398cf 100644 --- a/src/librustc/middle/intrinsicck.rs +++ b/src/librustc/middle/intrinsicck.rs @@ -163,7 +163,7 @@ impl<'a, 'gcx, 'tcx, 'v> Visitor<'v> for ExprVisitor<'a, 'gcx, 'tcx> { if let hir::ExprPath(..) = expr.node { match self.infcx.tcx.expect_def(expr.id) { Def::Fn(did) if self.def_id_is_transmute(did) => { - let typ = self.infcx.tcx.node_id_to_type(expr.id); + let typ = self.infcx.tcx.tables().node_id_to_type(expr.id); match typ.sty { ty::TyFnDef(.., ref bare_fn_ty) if bare_fn_ty.abi == RustIntrinsic => { let from = bare_fn_ty.sig.0.inputs[0]; diff --git a/src/librustc/middle/lang_items.rs b/src/librustc/middle/lang_items.rs index 078cce9c49..3175230ab6 100644 --- a/src/librustc/middle/lang_items.rs +++ b/src/librustc/middle/lang_items.rs @@ -59,7 +59,7 @@ impl LanguageItems { fn foo(_: LangItem) -> Option { None } LanguageItems { - items: vec!($(foo($variant)),*), + items: vec![$(foo($variant)),*], missing: Vec::new(), } } diff --git a/src/librustc/middle/liveness.rs b/src/librustc/middle/liveness.rs index db9dd82d49..46bea00cca 100644 --- a/src/librustc/middle/liveness.rs +++ b/src/librustc/middle/liveness.rs @@ -490,7 +490,7 @@ fn visit_expr(ir: &mut IrMaps, expr: &Expr) { // otherwise, live nodes are not required: hir::ExprIndex(..) | hir::ExprField(..) | hir::ExprTupField(..) | - hir::ExprVec(..) | hir::ExprCall(..) | hir::ExprMethodCall(..) | + hir::ExprArray(..) | hir::ExprCall(..) | hir::ExprMethodCall(..) | hir::ExprTup(..) | hir::ExprBinary(..) | hir::ExprAddrOf(..) | hir::ExprCast(..) | hir::ExprUnary(..) | hir::ExprBreak(_) | hir::ExprAgain(_) | hir::ExprLit(_) | hir::ExprRet(..) | @@ -1081,7 +1081,7 @@ impl<'a, 'tcx> Liveness<'a, 'tcx> { hir::ExprAssignOp(_, ref l, ref r) => { // an overloaded assign op is like a method call - if self.ir.tcx.is_method_call(expr.id) { + if self.ir.tcx.tables().is_method_call(expr.id) { let succ = self.propagate_through_expr(&l, succ); self.propagate_through_expr(&r, succ) } else { @@ -1095,7 +1095,7 @@ impl<'a, 'tcx> Liveness<'a, 'tcx> { // Uninteresting cases: just propagate in rev exec order - hir::ExprVec(ref exprs) => { + hir::ExprArray(ref exprs) => { self.propagate_through_exprs(&exprs[..], succ) } @@ -1113,8 +1113,8 @@ impl<'a, 'tcx> Liveness<'a, 'tcx> { hir::ExprCall(ref f, ref args) => { // FIXME(canndrew): This is_never should really be an is_uninhabited - let diverges = !self.ir.tcx.is_method_call(expr.id) && - self.ir.tcx.expr_ty_adjusted(&f).fn_ret().0.is_never(); + let diverges = !self.ir.tcx.tables().is_method_call(expr.id) && + self.ir.tcx.tables().expr_ty_adjusted(&f).fn_ret().0.is_never(); let succ = if diverges { self.s.exit_ln } else { @@ -1126,7 +1126,7 @@ impl<'a, 'tcx> Liveness<'a, 'tcx> { hir::ExprMethodCall(.., ref args) => { let method_call = ty::MethodCall::expr(expr.id); - let method_ty = self.ir.tcx.tables.borrow().method_map[&method_call].ty; + let method_ty = self.ir.tcx.tables().method_map[&method_call].ty; // FIXME(canndrew): This is_never should really be an is_uninhabited let succ = if method_ty.fn_ret().0.is_never() { self.s.exit_ln @@ -1409,7 +1409,7 @@ fn check_expr(this: &mut Liveness, expr: &Expr) { } hir::ExprAssignOp(_, ref l, _) => { - if !this.ir.tcx.is_method_call(expr.id) { + if !this.ir.tcx.tables().is_method_call(expr.id) { this.check_lvalue(&l); } @@ -1436,7 +1436,7 @@ fn check_expr(this: &mut Liveness, expr: &Expr) { hir::ExprCall(..) | hir::ExprMethodCall(..) | hir::ExprIf(..) | hir::ExprMatch(..) | hir::ExprWhile(..) | hir::ExprLoop(..) | hir::ExprIndex(..) | hir::ExprField(..) | hir::ExprTupField(..) | - hir::ExprVec(..) | hir::ExprTup(..) | hir::ExprBinary(..) | + hir::ExprArray(..) | hir::ExprTup(..) | hir::ExprBinary(..) | hir::ExprCast(..) | hir::ExprUnary(..) | hir::ExprRet(..) | hir::ExprBreak(..) | hir::ExprAgain(..) | hir::ExprLit(_) | hir::ExprBlock(..) | hir::ExprAddrOf(..) | @@ -1459,7 +1459,7 @@ fn check_fn(_v: &Liveness, impl<'a, 'tcx> Liveness<'a, 'tcx> { fn fn_ret(&self, id: NodeId) -> ty::Binder> { - let fn_ty = self.ir.tcx.node_id_to_type(id); + let fn_ty = self.ir.tcx.tables().node_id_to_type(id); match fn_ty.sty { ty::TyClosure(closure_def_id, substs) => self.ir.tcx.closure_type(closure_def_id, substs).sig.output(), @@ -1502,7 +1502,7 @@ impl<'a, 'tcx> Liveness<'a, 'tcx> { None if !body.stmts.is_empty() => match body.stmts.last().unwrap().node { hir::StmtSemi(ref e, _) => { - self.ir.tcx.expr_ty(&e) == fn_ret + self.ir.tcx.tables().expr_ty(&e) == fn_ret }, _ => false }, diff --git a/src/librustc/middle/mem_categorization.rs b/src/librustc/middle/mem_categorization.rs index 340a5ac8f8..e3ed13e1e4 100644 --- a/src/librustc/middle/mem_categorization.rs +++ b/src/librustc/middle/mem_categorization.rs @@ -74,7 +74,7 @@ use hir::def_id::DefId; use hir::map as ast_map; use infer::InferCtxt; use middle::const_qualif::ConstQualif; -use hir::def::Def; +use hir::def::{Def, CtorKind}; use ty::adjustment; use ty::{self, Ty, TyCtxt}; @@ -354,11 +354,7 @@ impl<'a, 'gcx, 'tcx> MemCategorizationContext<'a, 'gcx, 'tcx> { } fn expr_ty_adjusted(&self, expr: &hir::Expr) -> McResult> { - let unadjusted_ty = self.expr_ty(expr)?; - Ok(unadjusted_ty.adjust( - self.tcx(), expr.span, expr.id, - self.infcx.adjustments().get(&expr.id), - |method_call| self.infcx.node_method_ty(method_call))) + self.infcx.expr_ty_adjusted(expr) } fn node_ty(&self, id: ast::NodeId) -> McResult> { @@ -396,19 +392,21 @@ impl<'a, 'gcx, 'tcx> MemCategorizationContext<'a, 'gcx, 'tcx> { } Some(adjustment) => { - match *adjustment { - adjustment::AdjustDerefRef( - adjustment::AutoDerefRef { - autoref: None, unsize: None, autoderefs, ..}) => { + match adjustment.kind { + adjustment::Adjust::DerefRef { + autoderefs, + autoref: None, + unsize: false + } => { // Equivalent to *expr or something similar. self.cat_expr_autoderefd(expr, autoderefs) } - adjustment::AdjustNeverToAny(..) | - adjustment::AdjustReifyFnPointer | - adjustment::AdjustUnsafeFnPointer | - adjustment::AdjustMutToConstPointer | - adjustment::AdjustDerefRef(_) => { + adjustment::Adjust::NeverToAny | + adjustment::Adjust::ReifyFnPointer | + adjustment::Adjust::UnsafeFnPointer | + adjustment::Adjust::MutToConstPointer | + adjustment::Adjust::DerefRef {..} => { debug!("cat_expr({:?}): {:?}", adjustment, expr); @@ -503,7 +501,7 @@ impl<'a, 'gcx, 'tcx> MemCategorizationContext<'a, 'gcx, 'tcx> { hir::ExprClosure(..) | hir::ExprRet(..) | hir::ExprUnary(..) | hir::ExprMethodCall(..) | hir::ExprCast(..) | - hir::ExprVec(..) | hir::ExprTup(..) | hir::ExprIf(..) | + hir::ExprArray(..) | hir::ExprTup(..) | hir::ExprIf(..) | hir::ExprBinary(..) | hir::ExprWhile(..) | hir::ExprBlock(..) | hir::ExprLoop(..) | hir::ExprMatch(..) | hir::ExprLit(..) | hir::ExprBreak(..) | @@ -524,20 +522,11 @@ impl<'a, 'gcx, 'tcx> MemCategorizationContext<'a, 'gcx, 'tcx> { id, expr_ty, def); match def { - Def::Struct(..) | Def::Union(..) | Def::Variant(..) | Def::Const(..) | + Def::StructCtor(..) | Def::VariantCtor(..) | Def::Const(..) | Def::AssociatedConst(..) | Def::Fn(..) | Def::Method(..) => { Ok(self.cat_rvalue_node(id, span, expr_ty)) } - Def::Mod(_) | - Def::Trait(_) | Def::Enum(..) | Def::TyAlias(..) | Def::PrimTy(_) | - Def::TyParam(..) | - Def::Label(_) | Def::SelfTy(..) | - Def::AssociatedTy(..) => { - span_bug!(span, "Unexpected definition in \ - memory categorization: {:?}", def); - } - Def::Static(_, mutbl) => { Ok(Rc::new(cmt_ { id:id, @@ -598,7 +587,7 @@ impl<'a, 'gcx, 'tcx> MemCategorizationContext<'a, 'gcx, 'tcx> { })) } - Def::Err => bug!("Def::Err in memory categorization") + def => span_bug!(span, "unexpected definition in memory categorization: {:?}", def) } } @@ -1077,7 +1066,8 @@ impl<'a, 'gcx, 'tcx> MemCategorizationContext<'a, 'gcx, 'tcx> { // alone) because PatKind::Struct can also refer to variants. let cmt = match self.tcx().expect_def_or_none(pat.id) { Some(Def::Err) => return Err(()), - Some(Def::Variant(variant_did)) => { + Some(Def::Variant(variant_did)) | + Some(Def::VariantCtor(variant_did, ..)) => { // univariant enums do not need downcasts let enum_did = self.tcx().parent_def_id(variant_did).unwrap(); if !self.tcx().lookup_adt_def(enum_did).is_univariant() { @@ -1092,11 +1082,11 @@ impl<'a, 'gcx, 'tcx> MemCategorizationContext<'a, 'gcx, 'tcx> { match pat.node { PatKind::TupleStruct(_, ref subpats, ddpos) => { let expected_len = match self.tcx().expect_def(pat.id) { - Def::Variant(def_id) => { + Def::VariantCtor(def_id, CtorKind::Fn) => { let enum_def = self.tcx().parent_def_id(def_id).unwrap(); self.tcx().lookup_adt_def(enum_def).variant_with_id(def_id).fields.len() } - Def::Struct(..) => { + Def::StructCtor(_, CtorKind::Fn) => { match self.pat_ty(&pat)?.sty { ty::TyAdt(adt_def, _) => { adt_def.struct_variant().fields.len() @@ -1155,7 +1145,7 @@ impl<'a, 'gcx, 'tcx> MemCategorizationContext<'a, 'gcx, 'tcx> { self.cat_pattern_(subcmt, &subpat, op)?; } - PatKind::Vec(ref before, ref slice, ref after) => { + PatKind::Slice(ref before, ref slice, ref after) => { let context = InteriorOffsetKind::Pattern; let elt_cmt = self.cat_index(pat, cmt, context)?; for before_pat in before { diff --git a/src/librustc/middle/reachable.rs b/src/librustc/middle/reachable.rs index beffaff1e5..1a50d7aa0a 100644 --- a/src/librustc/middle/reachable.rs +++ b/src/librustc/middle/reachable.rs @@ -116,7 +116,7 @@ impl<'a, 'tcx, 'v> Visitor<'v> for ReachableContext<'a, 'tcx> { } hir::ExprMethodCall(..) => { let method_call = ty::MethodCall::expr(expr.id); - let def_id = self.tcx.tables.borrow().method_map[&method_call].def_id; + let def_id = self.tcx.tables().method_map[&method_call].def_id; // Mark the trait item (and, possibly, its default impl) as reachable // Or mark inherent impl item as reachable @@ -139,7 +139,7 @@ impl<'a, 'tcx> ReachableContext<'a, 'tcx> { fn new(tcx: TyCtxt<'a, 'tcx, 'tcx>) -> ReachableContext<'a, 'tcx> { let any_library = tcx.sess.crate_types.borrow().iter().any(|ty| { *ty == config::CrateTypeRlib || *ty == config::CrateTypeDylib || - *ty == config::CrateTypeRustcMacro + *ty == config::CrateTypeProcMacro }); ReachableContext { tcx: tcx, diff --git a/src/librustc/middle/region.rs b/src/librustc/middle/region.rs index 33110c61e8..30b735b9c2 100644 --- a/src/librustc/middle/region.rs +++ b/src/librustc/middle/region.rs @@ -478,12 +478,9 @@ impl RegionMaps { //! Returns the scope when temp created by expr_id will be cleaned up // check for a designated rvalue scope - match self.rvalue_scopes.borrow().get(&expr_id) { - Some(&s) => { - debug!("temporary_scope({:?}) = {:?} [custom]", expr_id, s); - return Some(s); - } - None => { } + if let Some(&s) = self.rvalue_scopes.borrow().get(&expr_id) { + debug!("temporary_scope({:?}) = {:?} [custom]", expr_id, s); + return Some(s); } let scope_map : &[CodeExtent] = &self.scope_map.borrow(); @@ -928,19 +925,15 @@ fn resolve_local(visitor: &mut RegionResolutionVisitor, local: &hir::Local) { // // FIXME(#6308) -- Note that `[]` patterns work more smoothly post-DST. - match local.init { - Some(ref expr) => { - record_rvalue_scope_if_borrow_expr(visitor, &expr, blk_scope); + if let Some(ref expr) = local.init { + record_rvalue_scope_if_borrow_expr(visitor, &expr, blk_scope); - let is_borrow = - if let Some(ref ty) = local.ty { is_borrowed_ty(&ty) } else { false }; + let is_borrow = + if let Some(ref ty) = local.ty { is_borrowed_ty(&ty) } else { false }; - if is_binding_pat(&local.pat) || is_borrow { - record_rvalue_scope(visitor, &expr, blk_scope); - } + if is_binding_pat(&local.pat) || is_borrow { + record_rvalue_scope(visitor, &expr, blk_scope); } - - None => { } } intravisit::walk_local(visitor, local); @@ -961,7 +954,7 @@ fn resolve_local(visitor: &mut RegionResolutionVisitor, local: &hir::Local) { field_pats.iter().any(|fp| is_binding_pat(&fp.node.pat)) } - PatKind::Vec(ref pats1, ref pats2, ref pats3) => { + PatKind::Slice(ref pats1, ref pats2, ref pats3) => { pats1.iter().any(|p| is_binding_pat(&p)) || pats2.iter().any(|p| is_binding_pat(&p)) || pats3.iter().any(|p| is_binding_pat(&p)) @@ -1012,7 +1005,7 @@ fn resolve_local(visitor: &mut RegionResolutionVisitor, local: &hir::Local) { visitor, &field.expr, blk_id); } } - hir::ExprVec(ref subexprs) | + hir::ExprArray(ref subexprs) | hir::ExprTup(ref subexprs) => { for subexpr in subexprs { record_rvalue_scope_if_borrow_expr( @@ -1023,16 +1016,12 @@ fn resolve_local(visitor: &mut RegionResolutionVisitor, local: &hir::Local) { record_rvalue_scope_if_borrow_expr(visitor, &subexpr, blk_id) } hir::ExprBlock(ref block) => { - match block.expr { - Some(ref subexpr) => { - record_rvalue_scope_if_borrow_expr( - visitor, &subexpr, blk_id); - } - None => { } + if let Some(ref subexpr) = block.expr { + record_rvalue_scope_if_borrow_expr( + visitor, &subexpr, blk_id); } } - _ => { - } + _ => {} } } diff --git a/src/librustc/middle/stability.rs b/src/librustc/middle/stability.rs index ccab427923..fd17e37878 100644 --- a/src/librustc/middle/stability.rs +++ b/src/librustc/middle/stability.rs @@ -555,11 +555,11 @@ pub fn check_expr<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, e: &hir::Expr, hir::ExprMethodCall(i, ..) => { span = i.span; let method_call = ty::MethodCall::expr(e.id); - tcx.tables.borrow().method_map[&method_call].def_id + tcx.tables().method_map[&method_call].def_id } hir::ExprField(ref base_e, ref field) => { span = field.span; - match tcx.expr_ty_adjusted(base_e).sty { + match tcx.tables().expr_ty_adjusted(base_e).sty { ty::TyAdt(def, _) => { def.struct_variant().field_named(field.node).did } @@ -569,7 +569,7 @@ pub fn check_expr<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, e: &hir::Expr, } hir::ExprTupField(ref base_e, ref field) => { span = field.span; - match tcx.expr_ty_adjusted(base_e).sty { + match tcx.tables().expr_ty_adjusted(base_e).sty { ty::TyAdt(def, _) => { def.struct_variant().fields[field.node].did } @@ -580,7 +580,7 @@ pub fn check_expr<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, e: &hir::Expr, } } hir::ExprStruct(_, ref expr_fields, _) => { - match tcx.expr_ty(e).sty { + match tcx.tables().expr_ty(e).sty { ty::TyAdt(adt, ..) => match adt.adt_kind() { AdtKind::Struct | AdtKind::Union => { // check the stability of each field that appears @@ -617,12 +617,8 @@ pub fn check_path<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, &Option)) { // Paths in import prefixes may have no resolution. match tcx.expect_def_or_none(id) { - Some(Def::PrimTy(..)) => {} - Some(Def::SelfTy(..)) => {} - Some(def) => { - maybe_do_stability_check(tcx, def.def_id(), path.span, cb); - } - None => {} + None | Some(Def::PrimTy(..)) | Some(Def::SelfTy(..)) => {} + Some(def) => maybe_do_stability_check(tcx, def.def_id(), path.span, cb) } } @@ -631,12 +627,7 @@ pub fn check_path_list_item<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, cb: &mut FnMut(DefId, Span, &Option<&Stability>, &Option)) { - match tcx.expect_def(item.node.id) { - Def::PrimTy(..) => {} - def => { - maybe_do_stability_check(tcx, def.def_id(), item.span, cb); - } - } + maybe_do_stability_check(tcx, tcx.expect_def(item.node.id).def_id(), item.span, cb); } pub fn check_pat<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, pat: &hir::Pat, @@ -646,7 +637,7 @@ pub fn check_pat<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, pat: &hir::Pat, debug!("check_pat(pat = {:?})", pat); if is_internal(tcx, pat.span) { return; } - let v = match tcx.pat_ty_opt(pat).map(|ty| &ty.sty) { + let v = match tcx.tables().pat_ty_opt(pat).map(|ty| &ty.sty) { Some(&ty::TyAdt(adt, _)) if !adt.is_enum() => adt.struct_variant(), _ => return, }; diff --git a/src/librustc/middle/weak_lang_items.rs b/src/librustc/middle/weak_lang_items.rs index c2f275e6de..2c08e17f8f 100644 --- a/src/librustc/middle/weak_lang_items.rs +++ b/src/librustc/middle/weak_lang_items.rs @@ -10,10 +10,11 @@ //! Validity checking for weak lang items -use session::config::{self, PanicStrategy}; +use session::config; use session::Session; use middle::lang_items; +use rustc_back::PanicStrategy; use syntax::ast; use syntax::parse::token::InternedString; use syntax_pos::Span; @@ -70,7 +71,7 @@ fn verify(sess: &Session, items: &lang_items::LanguageItems) { let needs_check = sess.crate_types.borrow().iter().any(|kind| { match *kind { config::CrateTypeDylib | - config::CrateTypeRustcMacro | + config::CrateTypeProcMacro | config::CrateTypeCdylib | config::CrateTypeExecutable | config::CrateTypeStaticlib => true, @@ -92,7 +93,7 @@ fn verify(sess: &Session, items: &lang_items::LanguageItems) { // symbols. Other panic runtimes ensure that the relevant symbols are // available to link things together, but they're never exercised. let mut whitelisted = HashSet::new(); - if sess.opts.cg.panic != PanicStrategy::Unwind { + if sess.panic_strategy() != PanicStrategy::Unwind { whitelisted.insert(lang_items::EhPersonalityLangItem); whitelisted.insert(lang_items::EhUnwindResumeLangItem); } diff --git a/src/librustc/mir/cache.rs b/src/librustc/mir/cache.rs index 1be7d00f07..bc9bbebb17 100644 --- a/src/librustc/mir/cache.rs +++ b/src/librustc/mir/cache.rs @@ -11,7 +11,7 @@ use std::cell::{Ref, RefCell}; use rustc_data_structures::indexed_vec::IndexVec; -use mir::repr::{Mir, BasicBlock}; +use mir::{Mir, BasicBlock}; use rustc_serialize as serialize; diff --git a/src/librustc/mir/mir_map.rs b/src/librustc/mir/mir_map.rs deleted file mode 100644 index 92de65798d..0000000000 --- a/src/librustc/mir/mir_map.rs +++ /dev/null @@ -1,38 +0,0 @@ -// Copyright 2016 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution and at -// http://rust-lang.org/COPYRIGHT. -// -// Licensed under the Apache License, Version 2.0 or the MIT license -// , at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - -use dep_graph::{DepGraph, DepNode, DepTrackingMap, DepTrackingMapConfig}; -use hir::def_id::DefId; -use mir::repr::Mir; -use std::marker::PhantomData; - -pub struct MirMap<'tcx> { - pub map: DepTrackingMap>, -} - -impl<'tcx> MirMap<'tcx> { - pub fn new(graph: DepGraph) -> Self { - MirMap { - map: DepTrackingMap::new(graph) - } - } -} - -pub struct MirMapConfig<'tcx> { - data: PhantomData<&'tcx ()> -} - -impl<'tcx> DepTrackingMapConfig for MirMapConfig<'tcx> { - type Key = DefId; - type Value = Mir<'tcx>; - fn to_dep_node(key: &DefId) -> DepNode { - DepNode::Mir(*key) - } -} diff --git a/src/librustc/mir/repr.rs b/src/librustc/mir/mod.rs similarity index 86% rename from src/librustc/mir/repr.rs rename to src/librustc/mir/mod.rs index c55a319d34..9d82006ac9 100644 --- a/src/librustc/mir/repr.rs +++ b/src/librustc/mir/mod.rs @@ -15,6 +15,7 @@ use rustc_data_structures::indexed_vec::{IndexVec, Idx}; use rustc_data_structures::control_flow_graph::dominators::{Dominators, dominators}; use rustc_data_structures::control_flow_graph::{GraphPredecessors, GraphSuccessors}; use rustc_data_structures::control_flow_graph::ControlFlowGraph; +use hir::def::CtorKind; use hir::def_id::DefId; use ty::subst::Substs; use ty::{self, AdtDef, ClosureSubsts, Region, Ty}; @@ -31,7 +32,11 @@ use std::vec::IntoIter; use syntax::ast::{self, Name}; use syntax_pos::Span; -use super::cache::Cache; +mod cache; +pub mod tcx; +pub mod visit; +pub mod transform; +pub mod traversal; macro_rules! newtype_index { ($name:ident, $debug_name:expr) => ( @@ -58,7 +63,8 @@ macro_rules! newtype_index { } /// Lowered representation of a single function. -#[derive(Clone, RustcEncodable, RustcDecodable, Debug)] +// Do not implement clone for Mir, its easy to do so accidently and its kind of expensive. +#[derive(RustcEncodable, RustcDecodable, Debug)] pub struct Mir<'tcx> { /// List of basic blocks. References to basic block use a newtyped index type `BasicBlock` /// that indexes into this vector. @@ -70,34 +76,42 @@ pub struct Mir<'tcx> { /// Rvalues promoted from this function, such as borrows of constants. /// Each of them is the Mir of a constant with the fn's type parameters - /// in scope, but no vars or args and a separate set of temps. + /// in scope, but a separate set of locals. pub promoted: IndexVec>, /// Return type of the function. pub return_ty: Ty<'tcx>, - /// Variables: these are stack slots corresponding to user variables. They may be - /// assigned many times. - pub var_decls: IndexVec>, - - /// Args: these are stack slots corresponding to the input arguments. - pub arg_decls: IndexVec>, + /// Declarations of locals. + /// + /// The first local is the return value pointer, followed by `arg_count` + /// locals for the function arguments, followed by any user-declared + /// variables and temporaries. + pub local_decls: IndexVec>, - /// Temp declarations: stack slots that for temporaries created by - /// the compiler. These are assigned once, but they are not SSA - /// values in that it is possible to borrow them and mutate them - /// through the resulting reference. - pub temp_decls: IndexVec>, + /// Number of arguments this function takes. + /// + /// Starting at local 1, `arg_count` locals will be provided by the caller + /// and can be assumed to be initialized. + /// + /// If this MIR was built for a constant, this will be 0. + pub arg_count: usize, /// Names and capture modes of all the closure upvars, assuming /// the first argument is either the closure or a reference to it. pub upvar_decls: Vec, + /// Mark an argument local (which must be a tuple) as getting passed as + /// its individual components at the LLVM level. + /// + /// This is used for the "rust-call" ABI. + pub spread_arg: Option, + /// A span representing this MIR, for error reporting pub span: Span, /// A cache for various calculations - cache: Cache + cache: cache::Cache } /// where execution begins @@ -108,23 +122,27 @@ impl<'tcx> Mir<'tcx> { visibility_scopes: IndexVec, promoted: IndexVec>, return_ty: Ty<'tcx>, - var_decls: IndexVec>, - arg_decls: IndexVec>, - temp_decls: IndexVec>, + local_decls: IndexVec>, + arg_count: usize, upvar_decls: Vec, span: Span) -> Self { + // We need `arg_count` locals, and one for the return pointer + assert!(local_decls.len() >= arg_count + 1, + "expected at least {} locals, got {}", arg_count + 1, local_decls.len()); + assert_eq!(local_decls[RETURN_POINTER].ty, return_ty); + Mir { basic_blocks: basic_blocks, visibility_scopes: visibility_scopes, promoted: promoted, return_ty: return_ty, - var_decls: var_decls, - arg_decls: arg_decls, - temp_decls: temp_decls, + local_decls: local_decls, + arg_count: arg_count, upvar_decls: upvar_decls, + spread_arg: None, span: span, - cache: Cache::new() + cache: cache::Cache::new() } } @@ -154,56 +172,66 @@ impl<'tcx> Mir<'tcx> { dominators(self) } - /// Maps locals (Arg's, Var's, Temp's and ReturnPointer, in that order) - /// to their index in the whole list of locals. This is useful if you - /// want to treat all locals the same instead of repeating yourself. - pub fn local_index(&self, lvalue: &Lvalue<'tcx>) -> Option { - let idx = match *lvalue { - Lvalue::Arg(arg) => arg.index(), - Lvalue::Var(var) => { - self.arg_decls.len() + - var.index() - } - Lvalue::Temp(temp) => { - self.arg_decls.len() + - self.var_decls.len() + - temp.index() + #[inline] + pub fn local_kind(&self, local: Local) -> LocalKind { + let index = local.0 as usize; + if index == 0 { + debug_assert!(self.local_decls[local].mutability == Mutability::Mut, + "return pointer should be mutable"); + + LocalKind::ReturnPointer + } else if index < self.arg_count + 1 { + LocalKind::Arg + } else if self.local_decls[local].name.is_some() { + LocalKind::Var + } else { + debug_assert!(self.local_decls[local].mutability == Mutability::Mut, + "temp should be mutable"); + + LocalKind::Temp + } + } + + /// Returns an iterator over all temporaries. + #[inline] + pub fn temps_iter<'a>(&'a self) -> impl Iterator + 'a { + (self.arg_count+1..self.local_decls.len()).filter_map(move |index| { + let local = Local::new(index); + if self.local_decls[local].source_info.is_none() { + Some(local) + } else { + None } - Lvalue::ReturnPointer => { - self.arg_decls.len() + - self.var_decls.len() + - self.temp_decls.len() + }) + } + + /// Returns an iterator over all user-declared locals. + #[inline] + pub fn vars_iter<'a>(&'a self) -> impl Iterator + 'a { + (self.arg_count+1..self.local_decls.len()).filter_map(move |index| { + let local = Local::new(index); + if self.local_decls[local].source_info.is_none() { + None + } else { + Some(local) } - Lvalue::Static(_) | - Lvalue::Projection(_) => return None - }; - Some(Local::new(idx)) + }) } - /// Counts the number of locals, such that local_index - /// will always return an index smaller than this count. - pub fn count_locals(&self) -> usize { - self.arg_decls.len() + - self.var_decls.len() + - self.temp_decls.len() + 1 + /// Returns an iterator over all function arguments. + #[inline] + pub fn args_iter(&self) -> impl Iterator { + let arg_count = self.arg_count; + (1..arg_count+1).map(Local::new) } - pub fn format_local(&self, local: Local) -> String { - let mut index = local.index(); - index = match index.checked_sub(self.arg_decls.len()) { - None => return format!("{:?}", Arg::new(index)), - Some(index) => index, - }; - index = match index.checked_sub(self.var_decls.len()) { - None => return format!("{:?}", Var::new(index)), - Some(index) => index, - }; - index = match index.checked_sub(self.temp_decls.len()) { - None => return format!("{:?}", Temp::new(index)), - Some(index) => index, - }; - debug_assert!(index == 0); - return "ReturnPointer".to_string() + /// Returns an iterator over all user-defined variables and compiler-generated temporaries (all + /// locals that are neither arguments nor the return pointer). + #[inline] + pub fn vars_and_temps_iter(&self) -> impl Iterator { + let arg_count = self.arg_count; + let local_count = self.local_decls.len(); + (arg_count+1..local_count).map(Local::new) } /// Changes a statement to a nop. This is both faster than deleting instructions and avoids @@ -301,53 +329,76 @@ pub enum BorrowKind { /////////////////////////////////////////////////////////////////////////// // Variables and temps -/// A "variable" is a binding declared by the user as part of the fn -/// decl, a let, etc. -#[derive(Clone, Debug, RustcEncodable, RustcDecodable)] -pub struct VarDecl<'tcx> { - /// `let mut x` vs `let x` - pub mutability: Mutability, - - /// name that user gave the variable; not that, internally, - /// mir references variables by index - pub name: Name, +newtype_index!(Local, "_"); - /// type inferred for this variable (`let x: ty = ...`) - pub ty: Ty<'tcx>, +pub const RETURN_POINTER: Local = Local(0); - /// source information (span, scope, etc.) for the declaration - pub source_info: SourceInfo, -} - -/// A "temp" is a temporary that we place on the stack. They are -/// anonymous, always mutable, and have only a type. -#[derive(Clone, Debug, RustcEncodable, RustcDecodable)] -pub struct TempDecl<'tcx> { - pub ty: Ty<'tcx>, +/// Classifies locals into categories. See `Mir::local_kind`. +#[derive(PartialEq, Eq, Debug)] +pub enum LocalKind { + /// User-declared variable binding + Var, + /// Compiler-introduced temporary + Temp, + /// Function argument + Arg, + /// Location of function's return value + ReturnPointer, } -/// A "arg" is one of the function's formal arguments. These are -/// anonymous and distinct from the bindings that the user declares. -/// -/// For example, in this function: -/// -/// ``` -/// fn foo((x, y): (i32, u32)) { ... } -/// ``` +/// A MIR local. /// -/// there is only one argument, of type `(i32, u32)`, but two bindings -/// (`x` and `y`). +/// This can be a binding declared by the user, a temporary inserted by the compiler, a function +/// argument, or the return pointer. #[derive(Clone, Debug, RustcEncodable, RustcDecodable)] -pub struct ArgDecl<'tcx> { +pub struct LocalDecl<'tcx> { + /// `let mut x` vs `let x`. + /// + /// Temporaries and the return pointer are always mutable. + pub mutability: Mutability, + + /// Type of this local. pub ty: Ty<'tcx>, - /// If true, this argument is a tuple after monomorphization, - /// and has to be collected from multiple actual arguments. - pub spread: bool, + /// Name of the local, used in debuginfo and pretty-printing. + /// + /// Note that function arguments can also have this set to `Some(_)` + /// to generate better debuginfo. + pub name: Option, + + /// For user-declared variables, stores their source information. + /// + /// For temporaries, this is `None`. + /// + /// This is the primary way to differentiate between user-declared + /// variables and compiler-generated temporaries. + pub source_info: Option, +} + +impl<'tcx> LocalDecl<'tcx> { + /// Create a new `LocalDecl` for a temporary. + #[inline] + pub fn new_temp(ty: Ty<'tcx>) -> Self { + LocalDecl { + mutability: Mutability::Mut, + ty: ty, + name: None, + source_info: None, + } + } - /// Either keywords::Invalid or the name of a single-binding - /// pattern associated with this argument. Useful for debuginfo. - pub debug_name: Name + /// Builds a `LocalDecl` for the return pointer. + /// + /// This must be inserted into the `local_decls` list as the first local. + #[inline] + pub fn new_return_pointer(return_ty: Ty) -> LocalDecl { + LocalDecl { + mutability: Mutability::Mut, + ty: return_ty, + source_info: None, + name: None, // FIXME maybe we do want some name here? + } + } } /// A closure capture, with its name and mode. @@ -439,7 +490,7 @@ pub enum TerminatorKind<'tcx> { /// continue. Emitted by build::scope::diverge_cleanup. Resume, - /// Indicates a normal return. The ReturnPointer lvalue should + /// Indicates a normal return. The return pointer lvalue should /// have been filled in by now. This should occur at most once. Return, @@ -756,31 +807,16 @@ impl<'tcx> Debug for Statement<'tcx> { /////////////////////////////////////////////////////////////////////////// // Lvalues -newtype_index!(Var, "var"); -newtype_index!(Temp, "tmp"); -newtype_index!(Arg, "arg"); -newtype_index!(Local, "local"); - /// A path to a value; something that can be evaluated without /// changing or disturbing program state. #[derive(Clone, PartialEq, RustcEncodable, RustcDecodable)] pub enum Lvalue<'tcx> { - /// local variable declared by the user - Var(Var), - - /// temporary introduced during lowering into MIR - Temp(Temp), - - /// formal parameter of the function; note that these are NOT the - /// bindings that the user declares, which are vars - Arg(Arg), + /// local variable + Local(Local), /// static or static mut variable Static(DefId), - /// the return pointer of the fn - ReturnPointer, - /// projection out of an lvalue (access a field, deref a pointer, etc) Projection(Box>), } @@ -862,24 +898,6 @@ impl<'tcx> Lvalue<'tcx> { elem: elem, })) } - - pub fn from_local(mir: &Mir<'tcx>, local: Local) -> Lvalue<'tcx> { - let mut index = local.index(); - index = match index.checked_sub(mir.arg_decls.len()) { - None => return Lvalue::Arg(Arg(index as u32)), - Some(index) => index, - }; - index = match index.checked_sub(mir.var_decls.len()) { - None => return Lvalue::Var(Var(index as u32)), - Some(index) => index, - }; - index = match index.checked_sub(mir.temp_decls.len()) { - None => return Lvalue::Temp(Temp(index as u32)), - Some(index) => index, - }; - debug_assert!(index == 0); - Lvalue::ReturnPointer - } } impl<'tcx> Debug for Lvalue<'tcx> { @@ -887,13 +905,9 @@ impl<'tcx> Debug for Lvalue<'tcx> { use self::Lvalue::*; match *self { - Var(id) => write!(fmt, "{:?}", id), - Arg(id) => write!(fmt, "{:?}", id), - Temp(id) => write!(fmt, "{:?}", id), + Local(id) => write!(fmt, "{:?}", id), Static(def_id) => write!(fmt, "{}", ty::tls::with(|tcx| tcx.item_path_str(def_id))), - ReturnPointer => - write!(fmt, "return"), Projection(ref data) => match data.elem { ProjectionElem::Downcast(ref adt_def, index) => @@ -1016,7 +1030,7 @@ pub enum CastKind { #[derive(Clone, Debug, PartialEq, Eq, RustcEncodable, RustcDecodable)] pub enum AggregateKind<'tcx> { - Vec, + Array, Tuple, /// The second field is variant number (discriminant), it's equal to 0 /// for struct and union expressions. The fourth field is active field @@ -1107,8 +1121,6 @@ impl<'tcx> Debug for Rvalue<'tcx> { } Aggregate(ref kind, ref lvs) => { - use self::AggregateKind::*; - fn fmt_tuple(fmt: &mut Formatter, lvs: &[Operand]) -> fmt::Result { let mut tuple_fmt = fmt.debug_tuple(""); for lv in lvs { @@ -1118,9 +1130,9 @@ impl<'tcx> Debug for Rvalue<'tcx> { } match *kind { - Vec => write!(fmt, "{:?}", lvs), + AggregateKind::Array => write!(fmt, "{:?}", lvs), - Tuple => { + AggregateKind::Tuple => { match lvs.len() { 0 => write!(fmt, "()"), 1 => write!(fmt, "({:?},)", lvs[0]), @@ -1128,15 +1140,15 @@ impl<'tcx> Debug for Rvalue<'tcx> { } } - Adt(adt_def, variant, substs, _) => { + AggregateKind::Adt(adt_def, variant, substs, _) => { let variant_def = &adt_def.variants[variant]; ppaux::parameterized(fmt, substs, variant_def.did, &[])?; - match variant_def.kind { - ty::VariantKind::Unit => Ok(()), - ty::VariantKind::Tuple => fmt_tuple(fmt, lvs), - ty::VariantKind::Struct => { + match variant_def.ctor_kind { + CtorKind::Const => Ok(()), + CtorKind::Fn => fmt_tuple(fmt, lvs), + CtorKind::Fictive => { let mut struct_fmt = fmt.debug_struct(""); for (field, lv) in variant_def.fields.iter().zip(lvs) { struct_fmt.field(&field.name.as_str(), lv); @@ -1146,7 +1158,7 @@ impl<'tcx> Debug for Rvalue<'tcx> { } } - Closure(def_id, _) => ty::tls::with(|tcx| { + AggregateKind::Closure(def_id, _) => ty::tls::with(|tcx| { if let Some(node_id) = tcx.map.as_local_node_id(def_id) { let name = format!("[closure@{:?}]", tcx.map.span(node_id)); let mut struct_fmt = fmt.debug_struct(&name); diff --git a/src/librustc/mir/tcx.rs b/src/librustc/mir/tcx.rs index 74ad6c602f..f9afbaf104 100644 --- a/src/librustc/mir/tcx.rs +++ b/src/librustc/mir/tcx.rs @@ -13,7 +13,7 @@ * building is complete. */ -use mir::repr::*; +use mir::*; use ty::subst::{Subst, Substs}; use ty::{self, AdtDef, Ty, TyCtxt}; use ty::fold::{TypeFoldable, TypeFolder, TypeVisitor}; @@ -49,12 +49,17 @@ impl<'a, 'gcx, 'tcx> LvalueTy<'tcx> { -> LvalueTy<'tcx> { match *elem { - ProjectionElem::Deref => + ProjectionElem::Deref => { + let ty = self.to_ty(tcx) + .builtin_deref(true, ty::LvaluePreference::NoPreference) + .unwrap_or_else(|| { + bug!("deref projection of non-dereferencable ty {:?}", self) + }) + .ty; LvalueTy::Ty { - ty: self.to_ty(tcx).builtin_deref(true, ty::LvaluePreference::NoPreference) - .unwrap() - .ty - }, + ty: ty, + } + } ProjectionElem::Index(_) | ProjectionElem::ConstantIndex { .. } => LvalueTy::Ty { ty: self.to_ty(tcx).builtin_index().unwrap() @@ -116,18 +121,12 @@ impl<'tcx> TypeFoldable<'tcx> for LvalueTy<'tcx> { impl<'tcx> Lvalue<'tcx> { pub fn ty<'a, 'gcx>(&self, mir: &Mir<'tcx>, tcx: TyCtxt<'a, 'gcx, 'tcx>) -> LvalueTy<'tcx> { - match self { - &Lvalue::Var(index) => - LvalueTy::Ty { ty: mir.var_decls[index].ty }, - &Lvalue::Temp(index) => - LvalueTy::Ty { ty: mir.temp_decls[index].ty }, - &Lvalue::Arg(index) => - LvalueTy::Ty { ty: mir.arg_decls[index].ty }, - &Lvalue::Static(def_id) => + match *self { + Lvalue::Local(index) => + LvalueTy::Ty { ty: mir.local_decls[index].ty }, + Lvalue::Static(def_id) => LvalueTy::Ty { ty: tcx.lookup_item_type(def_id).ty }, - &Lvalue::ReturnPointer => - LvalueTy::Ty { ty: mir.return_ty }, - &Lvalue::Projection(ref proj) => + Lvalue::Projection(ref proj) => proj.base.ty(mir, tcx).projection_ty(tcx, &proj.elem), } } @@ -164,7 +163,7 @@ impl<'tcx> Rvalue<'tcx> { let lhs_ty = lhs.ty(mir, tcx); let rhs_ty = rhs.ty(mir, tcx); let ty = op.ty(tcx, lhs_ty, rhs_ty); - let ty = tcx.mk_tup(vec![ty, tcx.types.bool]); + let ty = tcx.intern_tup(&[ty, tcx.types.bool]); Some(ty) } &Rvalue::UnaryOp(_, ref operand) => { @@ -175,7 +174,7 @@ impl<'tcx> Rvalue<'tcx> { } &Rvalue::Aggregate(ref ak, ref ops) => { match *ak { - AggregateKind::Vec => { + AggregateKind::Array => { if let Some(operand) = ops.get(0) { let ty = operand.ty(mir, tcx); Some(tcx.mk_array(ty, ops.len())) @@ -185,7 +184,7 @@ impl<'tcx> Rvalue<'tcx> { } AggregateKind::Tuple => { Some(tcx.mk_tup( - ops.iter().map(|op| op.ty(mir, tcx)).collect() + ops.iter().map(|op| op.ty(mir, tcx)) )) } AggregateKind::Adt(def, _, substs, _) => { diff --git a/src/librustc/mir/transform.rs b/src/librustc/mir/transform.rs index 8cd5f5844d..3576ae662a 100644 --- a/src/librustc/mir/transform.rs +++ b/src/librustc/mir/transform.rs @@ -11,8 +11,7 @@ use dep_graph::DepNode; use hir; use hir::map::DefPathData; -use mir::mir_map::MirMap; -use mir::repr::{Mir, Promoted}; +use mir::{Mir, Promoted}; use ty::TyCtxt; use syntax::ast::NodeId; use util::common::time; @@ -85,12 +84,11 @@ pub trait Pass { fn disambiguator<'a>(&'a self) -> Option> { None } } -/// A pass which inspects the whole MirMap. +/// A pass which inspects the whole Mir map. pub trait MirMapPass<'tcx>: Pass { fn run_pass<'a>( &mut self, tcx: TyCtxt<'a, 'tcx, 'tcx>, - map: &mut MirMap<'tcx>, hooks: &mut [Box MirPassHook<'s>>]); } @@ -114,13 +112,18 @@ pub trait MirPass<'tcx>: Pass { impl<'tcx, T: MirPass<'tcx>> MirMapPass<'tcx> for T { fn run_pass<'a>(&mut self, tcx: TyCtxt<'a, 'tcx, 'tcx>, - map: &mut MirMap<'tcx>, hooks: &mut [Box MirPassHook<'s>>]) { - let def_ids = map.map.keys(); + let def_ids = tcx.mir_map.borrow().keys(); for def_id in def_ids { + if !def_id.is_local() { + continue; + } + let _task = tcx.dep_graph.in_task(DepNode::Mir(def_id)); - let mir = map.map.get_mut(&def_id).unwrap(); + let mir = &mut tcx.mir_map.borrow()[&def_id].borrow_mut(); + tcx.dep_graph.write(DepNode::Mir(def_id)); + let id = tcx.map.as_local_node_id(def_id).unwrap(); let src = MirSource::from_node(tcx, id); @@ -163,11 +166,11 @@ impl<'a, 'tcx> Passes { passes } - pub fn run_passes(&mut self, tcx: TyCtxt<'a, 'tcx, 'tcx>, map: &mut MirMap<'tcx>) { + pub fn run_passes(&mut self, tcx: TyCtxt<'a, 'tcx, 'tcx>) { let Passes { ref mut passes, ref mut plugin_passes, ref mut pass_hooks } = *self; for pass in plugin_passes.iter_mut().chain(passes.iter_mut()) { time(tcx.sess.time_passes(), &*pass.name(), - || pass.run_pass(tcx, map, pass_hooks)); + || pass.run_pass(tcx, pass_hooks)); } } diff --git a/src/librustc/mir/traversal.rs b/src/librustc/mir/traversal.rs index 1af5123b4d..6057e7ec7e 100644 --- a/src/librustc/mir/traversal.rs +++ b/src/librustc/mir/traversal.rs @@ -13,7 +13,7 @@ use std::vec; use rustc_data_structures::bitvec::BitVector; use rustc_data_structures::indexed_vec::Idx; -use super::repr::*; +use super::*; /// Preorder traversal of a graph. /// diff --git a/src/librustc/mir/visit.rs b/src/librustc/mir/visit.rs index 2c58d35973..b5da304a10 100644 --- a/src/librustc/mir/visit.rs +++ b/src/librustc/mir/visit.rs @@ -12,7 +12,7 @@ use middle::const_val::ConstVal; use hir::def_id::DefId; use ty::subst::Substs; use ty::{ClosureSubsts, Region, Ty}; -use mir::repr::*; +use mir::*; use rustc_const_math::ConstUsize; use rustc_data_structures::tuple_slice::TupleSlice; use rustc_data_structures::indexed_vec::Idx; @@ -157,14 +157,14 @@ macro_rules! make_mir_visitor { fn visit_projection(&mut self, lvalue: & $($mutability)* LvalueProjection<'tcx>, - context: LvalueContext, + context: LvalueContext<'tcx>, location: Location) { self.super_projection(lvalue, context, location); } fn visit_projection_elem(&mut self, lvalue: & $($mutability)* LvalueElem<'tcx>, - context: LvalueContext, + context: LvalueContext<'tcx>, location: Location) { self.super_projection_elem(lvalue, context, location); } @@ -236,19 +236,9 @@ macro_rules! make_mir_visitor { self.super_typed_const_val(val, location); } - fn visit_var_decl(&mut self, - var_decl: & $($mutability)* VarDecl<'tcx>) { - self.super_var_decl(var_decl); - } - - fn visit_temp_decl(&mut self, - temp_decl: & $($mutability)* TempDecl<'tcx>) { - self.super_temp_decl(temp_decl); - } - - fn visit_arg_decl(&mut self, - arg_decl: & $($mutability)* ArgDecl<'tcx>) { - self.super_arg_decl(arg_decl); + fn visit_local_decl(&mut self, + local_decl: & $($mutability)* LocalDecl<'tcx>) { + self.super_local_decl(local_decl); } fn visit_visibility_scope(&mut self, @@ -272,16 +262,8 @@ macro_rules! make_mir_visitor { self.visit_ty(&$($mutability)* mir.return_ty); - for var_decl in &$($mutability)* mir.var_decls { - self.visit_var_decl(var_decl); - } - - for arg_decl in &$($mutability)* mir.arg_decls { - self.visit_arg_decl(arg_decl); - } - - for temp_decl in &$($mutability)* mir.temp_decls { - self.visit_temp_decl(temp_decl); + for local_decl in &$($mutability)* mir.local_decls { + self.visit_local_decl(local_decl); } self.visit_span(&$($mutability)* mir.span); @@ -531,7 +513,7 @@ macro_rules! make_mir_visitor { Rvalue::Aggregate(ref $($mutability)* kind, ref $($mutability)* operands) => { match *kind { - AggregateKind::Vec => { + AggregateKind::Array => { } AggregateKind::Tuple => { } @@ -584,10 +566,7 @@ macro_rules! make_mir_visitor { context: LvalueContext<'tcx>, location: Location) { match *lvalue { - Lvalue::Var(_) | - Lvalue::Temp(_) | - Lvalue::Arg(_) | - Lvalue::ReturnPointer => { + Lvalue::Local(_) => { } Lvalue::Static(ref $($mutability)* def_id) => { self.visit_def_id(def_id, location); @@ -600,7 +579,7 @@ macro_rules! make_mir_visitor { fn super_projection(&mut self, proj: & $($mutability)* LvalueProjection<'tcx>, - context: LvalueContext, + context: LvalueContext<'tcx>, location: Location) { let Projection { ref $($mutability)* base, @@ -617,7 +596,7 @@ macro_rules! make_mir_visitor { fn super_projection_elem(&mut self, proj: & $($mutability)* LvalueElem<'tcx>, - _context: LvalueContext, + _context: LvalueContext<'tcx>, location: Location) { match *proj { ProjectionElem::Deref => { @@ -639,37 +618,19 @@ macro_rules! make_mir_visitor { } } - fn super_var_decl(&mut self, - var_decl: & $($mutability)* VarDecl<'tcx>) { - let VarDecl { + fn super_local_decl(&mut self, + local_decl: & $($mutability)* LocalDecl<'tcx>) { + let LocalDecl { mutability: _, - name: _, ref $($mutability)* ty, + name: _, ref $($mutability)* source_info, - } = *var_decl; - - self.visit_ty(ty); - self.visit_source_info(source_info); - } - - fn super_temp_decl(&mut self, - temp_decl: & $($mutability)* TempDecl<'tcx>) { - let TempDecl { - ref $($mutability)* ty, - } = *temp_decl; - - self.visit_ty(ty); - } - - fn super_arg_decl(&mut self, - arg_decl: & $($mutability)* ArgDecl<'tcx>) { - let ArgDecl { - ref $($mutability)* ty, - spread: _, - debug_name: _ - } = *arg_decl; + } = *local_decl; self.visit_ty(ty); + if let Some(ref $($mutability)* info) = *source_info { + self.visit_source_info(info); + } } fn super_visibility_scope(&mut self, @@ -778,7 +739,7 @@ macro_rules! make_mir_visitor { make_mir_visitor!(Visitor,); make_mir_visitor!(MutVisitor,mut); -#[derive(Copy, Clone, Debug)] +#[derive(Copy, Clone, Debug, PartialEq, Eq)] pub enum LvalueContext<'tcx> { // Appears as LHS of an assignment Store, diff --git a/src/librustc/session/config.rs b/src/librustc/session/config.rs index 5c0f718ad2..63eabd5212 100644 --- a/src/librustc/session/config.rs +++ b/src/librustc/session/config.rs @@ -19,6 +19,7 @@ pub use self::DebugInfoLevel::*; use session::{early_error, early_warn, Session}; use session::search_paths::SearchPaths; +use rustc_back::PanicStrategy; use rustc_back::target::Target; use lint; use middle::cstore; @@ -288,6 +289,11 @@ top_level_options!( alt_std_name: Option [TRACKED], // Indicates how the compiler should treat unstable features unstable_features: UnstableFeatures [TRACKED], + + // Indicates whether this run of the compiler is actually rustdoc. This + // is currently just a hack and will be removed eventually, so please + // try to not rely on this too much. + actually_rustdoc: bool [TRACKED], } ); @@ -440,6 +446,7 @@ pub fn basic_options() -> Options { libs: Vec::new(), unstable_features: UnstableFeatures::Disallow, debug_assertions: true, + actually_rustdoc: false, } } @@ -475,7 +482,7 @@ pub enum CrateType { CrateTypeRlib, CrateTypeStaticlib, CrateTypeCdylib, - CrateTypeRustcMacro, + CrateTypeProcMacro, } #[derive(Clone, Hash)] @@ -493,21 +500,6 @@ impl Passes { } } -#[derive(Clone, PartialEq, Hash, RustcEncodable, RustcDecodable)] -pub enum PanicStrategy { - Unwind, - Abort, -} - -impl PanicStrategy { - pub fn desc(&self) -> &str { - match *self { - PanicStrategy::Unwind => "unwind", - PanicStrategy::Abort => "abort", - } - } -} - /// Declare a macro that will define all CodegenOptions/DebuggingOptions fields and parsers all /// at once. The goal of this macro is to define an interface that can be /// programmatically used by the option parser in order to initialize the struct @@ -621,7 +613,8 @@ macro_rules! options { #[allow(dead_code)] mod $mod_set { - use super::{$struct_name, Passes, SomePasses, AllPasses, PanicStrategy}; + use super::{$struct_name, Passes, SomePasses, AllPasses}; + use rustc_back::PanicStrategy; $( pub fn $opt(cg: &mut $struct_name, v: Option<&str>) -> bool { @@ -722,7 +715,7 @@ macro_rules! options { true } v => { - let mut passes = vec!(); + let mut passes = vec![]; if parse_list(&mut passes, v) { *slot = SomePasses(passes); true @@ -733,10 +726,10 @@ macro_rules! options { } } - fn parse_panic_strategy(slot: &mut PanicStrategy, v: Option<&str>) -> bool { + fn parse_panic_strategy(slot: &mut Option, v: Option<&str>) -> bool { match v { - Some("unwind") => *slot = PanicStrategy::Unwind, - Some("abort") => *slot = PanicStrategy::Abort, + Some("unwind") => *slot = Some(PanicStrategy::Unwind), + Some("abort") => *slot = Some(PanicStrategy::Abort), _ => return false } true @@ -810,7 +803,7 @@ options! {CodegenOptions, CodegenSetter, basic_codegen_options, "explicitly enable the cfg(debug_assertions) directive"), inline_threshold: Option = (None, parse_opt_uint, [TRACKED], "set the inlining threshold for"), - panic: PanicStrategy = (PanicStrategy::Unwind, parse_panic_strategy, + panic: Option = (None, parse_panic_strategy, [TRACKED], "panic strategy to compile crate with"), } @@ -925,6 +918,8 @@ options! {DebuggingOptions, DebuggingSetter, basic_debugging_options, "the directory the MIR is dumped into"), perf_stats: bool = (false, parse_bool, [UNTRACKED], "print some performance-related statistics"), + hir_stats: bool = (false, parse_bool, [UNTRACKED], + "print some statistics about AST and HIR"), } pub fn default_lib_output() -> CrateType { @@ -940,7 +935,7 @@ pub fn default_configuration(sess: &Session) -> ast::CrateConfig { let os = &sess.target.target.target_os; let env = &sess.target.target.target_env; let vendor = &sess.target.target.target_vendor; - let max_atomic_width = sess.target.target.options.max_atomic_width; + let max_atomic_width = sess.target.target.max_atomic_width(); let fam = if let Some(ref fam) = sess.target.target.options.target_family { intern(fam) @@ -979,8 +974,8 @@ pub fn default_configuration(sess: &Session) -> ast::CrateConfig { if sess.opts.debug_assertions { ret.push(attr::mk_word_item(InternedString::new("debug_assertions"))); } - if sess.opts.crate_types.contains(&CrateTypeRustcMacro) { - ret.push(attr::mk_word_item(InternedString::new("rustc_macro"))); + if sess.opts.crate_types.contains(&CrateTypeProcMacro) { + ret.push(attr::mk_word_item(InternedString::new("proc_macro"))); } return ret; } @@ -1244,10 +1239,9 @@ pub fn rustc_optgroups() -> Vec { pub fn parse_cfgspecs(cfgspecs: Vec ) -> ast::CrateConfig { cfgspecs.into_iter().map(|s| { let sess = parse::ParseSess::new(); - let mut parser = parse::new_parser_from_source_str(&sess, - Vec::new(), - "cfgspec".to_string(), - s.to_string()); + let mut parser = + parse::new_parser_from_source_str(&sess, "cfgspec".to_string(), s.to_string()); + let meta_item = panictry!(parser.parse_meta_item()); if !parser.reader.is_eof() { @@ -1301,7 +1295,7 @@ pub fn build_session_options_and_crate_config(matches: &getopts::Matches) let crate_types = parse_crate_types_from_list(unparsed_crate_types) .unwrap_or_else(|e| early_error(error_format, &e[..])); - let mut lint_opts = vec!(); + let mut lint_opts = vec![]; let mut describe_lints = false; for &level in &[lint::Allow, lint::Warn, lint::Deny, lint::Forbid] { @@ -1537,6 +1531,7 @@ pub fn build_session_options_and_crate_config(matches: &getopts::Matches) libs: libs, unstable_features: UnstableFeatures::from_environment(), debug_assertions: debug_assertions, + actually_rustdoc: false, }, cfg) } @@ -1552,7 +1547,7 @@ pub fn parse_crate_types_from_list(list_list: Vec) -> Result CrateTypeDylib, "cdylib" => CrateTypeCdylib, "bin" => CrateTypeExecutable, - "rustc-macro" => CrateTypeRustcMacro, + "proc-macro" => CrateTypeProcMacro, _ => { return Err(format!("unknown crate type: `{}`", part)); @@ -1636,7 +1631,7 @@ impl fmt::Display for CrateType { CrateTypeRlib => "rlib".fmt(f), CrateTypeStaticlib => "staticlib".fmt(f), CrateTypeCdylib => "cdylib".fmt(f), - CrateTypeRustcMacro => "rustc-macro".fmt(f), + CrateTypeProcMacro => "proc-macro".fmt(f), } } } @@ -1666,10 +1661,11 @@ mod dep_tracking { use std::collections::BTreeMap; use std::hash::Hash; use std::path::PathBuf; - use super::{Passes, PanicStrategy, CrateType, OptLevel, DebugInfoLevel, - OutputTypes, Externs, ErrorOutputType}; use std::collections::hash_map::DefaultHasher; + use super::{Passes, CrateType, OptLevel, DebugInfoLevel, + OutputTypes, Externs, ErrorOutputType}; use syntax::feature_gate::UnstableFeatures; + use rustc_back::PanicStrategy; pub trait DepTrackingHash { fn hash(&self, &mut DefaultHasher, ErrorOutputType); @@ -1708,6 +1704,7 @@ mod dep_tracking { impl_dep_tracking_hash_via_hash!(Option); impl_dep_tracking_hash_via_hash!(Option); impl_dep_tracking_hash_via_hash!(Option); + impl_dep_tracking_hash_via_hash!(Option); impl_dep_tracking_hash_via_hash!(Option); impl_dep_tracking_hash_via_hash!(Option); impl_dep_tracking_hash_via_hash!(CrateType); @@ -1774,7 +1771,8 @@ mod tests { use std::iter::FromIterator; use std::path::PathBuf; use std::rc::Rc; - use super::{OutputType, OutputTypes, Externs, PanicStrategy}; + use super::{OutputType, OutputTypes, Externs}; + use rustc_back::PanicStrategy; use syntax::{ast, attr}; use syntax::parse::token::InternedString; use syntax::codemap::dummy_spanned; @@ -2320,7 +2318,7 @@ mod tests { assert!(reference.dep_tracking_hash() != opts.dep_tracking_hash()); opts = reference.clone(); - opts.cg.panic = PanicStrategy::Abort; + opts.cg.panic = Some(PanicStrategy::Abort); assert!(reference.dep_tracking_hash() != opts.dep_tracking_hash()); } diff --git a/src/librustc/session/filesearch.rs b/src/librustc/session/filesearch.rs index a3eea324fd..82c2425aea 100644 --- a/src/librustc/session/filesearch.rs +++ b/src/librustc/session/filesearch.rs @@ -12,6 +12,7 @@ pub use self::FileMatch::*; +use std::borrow::Cow; use std::collections::HashSet; use std::env; use std::fs; @@ -67,33 +68,32 @@ impl<'a> FileSearch<'a> { { self.for_each_lib_search_path(|lib_search_path, kind| { debug!("searching {}", lib_search_path.display()); - match fs::read_dir(lib_search_path) { - Ok(files) => { - let files = files.filter_map(|p| p.ok().map(|s| s.path())) - .collect::>(); - fn is_rlib(p: &Path) -> bool { - p.extension().and_then(|s| s.to_str()) == Some("rlib") + let files = match fs::read_dir(lib_search_path) { + Ok(files) => files, + Err(..) => return, + }; + let files = files.filter_map(|p| p.ok().map(|s| s.path())) + .collect::>(); + fn is_rlib(p: &Path) -> bool { + p.extension() == Some("rlib".as_ref()) + } + // Reading metadata out of rlibs is faster, and if we find both + // an rlib and a dylib we only read one of the files of + // metadata, so in the name of speed, bring all rlib files to + // the front of the search list. + let files1 = files.iter().filter(|p| is_rlib(p)); + let files2 = files.iter().filter(|p| !is_rlib(p)); + for path in files1.chain(files2) { + debug!("testing {}", path.display()); + let maybe_picked = pick(path, kind); + match maybe_picked { + FileMatches => { + debug!("picked {}", path.display()); } - // Reading metadata out of rlibs is faster, and if we find both - // an rlib and a dylib we only read one of the files of - // metadata, so in the name of speed, bring all rlib files to - // the front of the search list. - let files1 = files.iter().filter(|p| is_rlib(p)); - let files2 = files.iter().filter(|p| !is_rlib(p)); - for path in files1.chain(files2) { - debug!("testing {}", path.display()); - let maybe_picked = pick(path, kind); - match maybe_picked { - FileMatches => { - debug!("picked {}", path.display()); - } - FileDoesntMatch => { - debug!("rejected {}", path.display()); - } - } + FileDoesntMatch => { + debug!("rejected {}", path.display()); } } - Err(..) => (), } }); } @@ -123,8 +123,8 @@ impl<'a> FileSearch<'a> { // Returns a list of directories where target-specific tool binaries are located. pub fn get_tools_search_paths(&self) -> Vec { let mut p = PathBuf::from(self.sysroot); - p.push(&find_libdir(self.sysroot)); - p.push(&rustlibdir()); + p.push(find_libdir(self.sysroot).as_ref()); + p.push(RUST_LIB_DIR); p.push(&self.triple); p.push("bin"); vec![p] @@ -132,9 +132,9 @@ impl<'a> FileSearch<'a> { } pub fn relative_target_lib_path(sysroot: &Path, target_triple: &str) -> PathBuf { - let mut p = PathBuf::from(&find_libdir(sysroot)); + let mut p = PathBuf::from(find_libdir(sysroot).as_ref()); assert!(p.is_relative()); - p.push(&rustlibdir()); + p.push(RUST_LIB_DIR); p.push(target_triple); p.push("lib"); p @@ -166,7 +166,7 @@ pub fn get_or_default_sysroot() -> PathBuf { } // The name of the directory rustc expects libraries to be located. -fn find_libdir(sysroot: &Path) -> String { +fn find_libdir(sysroot: &Path) -> Cow<'static, str> { // FIXME: This is a quick hack to make the rustc binary able to locate // Rust libraries in Linux environments where libraries might be installed // to lib64/lib32. This would be more foolproof by basing the sysroot off @@ -176,31 +176,23 @@ fn find_libdir(sysroot: &Path) -> String { // "lib" (i.e. non-default), this value is used (see issue #16552). match option_env!("CFG_LIBDIR_RELATIVE") { - Some(libdir) if libdir != "lib" => return libdir.to_string(), - _ => if sysroot.join(&primary_libdir_name()).join(&rustlibdir()).exists() { - return primary_libdir_name(); + Some(libdir) if libdir != "lib" => return libdir.into(), + _ => if sysroot.join(PRIMARY_LIB_DIR).join(RUST_LIB_DIR).exists() { + return PRIMARY_LIB_DIR.into(); } else { - return secondary_libdir_name(); + return SECONDARY_LIB_DIR.into(); } } #[cfg(target_pointer_width = "64")] - fn primary_libdir_name() -> String { - "lib64".to_string() - } + const PRIMARY_LIB_DIR: &'static str = "lib64"; #[cfg(target_pointer_width = "32")] - fn primary_libdir_name() -> String { - "lib32".to_string() - } + const PRIMARY_LIB_DIR: &'static str = "lib32"; - fn secondary_libdir_name() -> String { - "lib".to_string() - } + const SECONDARY_LIB_DIR: &'static str = "lib"; } // The name of rustc's own place to organize libraries. // Used to be "rustc", now the default is "rustlib" -pub fn rustlibdir() -> String { - "rustlib".to_string() -} +const RUST_LIB_DIR: &'static str = "rustlib"; diff --git a/src/librustc/session/mod.rs b/src/librustc/session/mod.rs index 268dbd70bb..b4dadbf796 100644 --- a/src/librustc/session/mod.rs +++ b/src/librustc/session/mod.rs @@ -15,9 +15,9 @@ use lint; use middle::cstore::CrateStore; use middle::dependency_format; use session::search_paths::PathKind; -use session::config::{DebugInfoLevel, PanicStrategy}; +use session::config::DebugInfoLevel; use ty::tls; -use util::nodemap::{NodeMap, FnvHashMap}; +use util::nodemap::{NodeMap, FnvHashMap, FnvHashSet}; use util::common::duration_to_secs_str; use mir::transform as mir_pass; @@ -33,6 +33,7 @@ use syntax::{ast, codemap}; use syntax::feature_gate::AttributeType; use syntax_pos::{Span, MultiSpan}; +use rustc_back::PanicStrategy; use rustc_back::target::Target; use rustc_data_structures::flock; use llvm; @@ -42,6 +43,7 @@ use std::cell::{self, Cell, RefCell}; use std::collections::HashMap; use std::env; use std::ffi::CString; +use std::io::Write; use std::rc::Rc; use std::fmt; use std::time::Duration; @@ -72,7 +74,11 @@ pub struct Session { pub local_crate_source_file: Option, pub working_dir: PathBuf, pub lint_store: RefCell, - pub lints: RefCell>>, + pub lints: RefCell>>, + /// Set of (LintId, span, message) tuples tracking lint (sub)diagnostics + /// that have been set once, but should not be set again, in order to avoid + /// redundantly verbose output (Issue #24690). + pub one_time_diagnostics: RefCell>, pub plugin_llvm_passes: RefCell>, pub mir_passes: RefCell, pub plugin_attributes: RefCell>, @@ -116,6 +122,8 @@ pub struct PerfStats { pub incr_comp_hashes_time: Cell, // The number of incr. comp. hash computations performed pub incr_comp_hashes_count: Cell, + // The number of bytes hashed when computing ICH values + pub incr_comp_bytes_hashed: Cell, // The accumulated time spent on computing symbol hashes pub symbol_hash_time: Cell, } @@ -254,17 +262,26 @@ impl Session { lint: &'static lint::Lint, id: ast::NodeId, sp: Span, - msg: String) { + msg: String) + { + self.add_lint_diagnostic(lint, id, (sp, &msg[..])) + } + pub fn add_lint_diagnostic(&self, + lint: &'static lint::Lint, + id: ast::NodeId, + msg: M) + where M: lint::IntoEarlyLint, + { let lint_id = lint::LintId::of(lint); let mut lints = self.lints.borrow_mut(); + let early_lint = msg.into_early_lint(lint_id); if let Some(arr) = lints.get_mut(&id) { - let tuple = (lint_id, sp, msg); - if !arr.contains(&tuple) { - arr.push(tuple); + if !arr.contains(&early_lint) { + arr.push(early_lint); } return; } - lints.insert(id, vec!((lint_id, sp, msg))); + lints.insert(id, vec![early_lint]); } pub fn reserve_node_ids(&self, count: usize) -> ast::NodeId { let id = self.next_node_id.get(); @@ -284,6 +301,35 @@ impl Session { pub fn diagnostic<'a>(&'a self) -> &'a errors::Handler { &self.parse_sess.span_diagnostic } + + /// Analogous to calling `.span_note` on the given DiagnosticBuilder, but + /// deduplicates on lint ID, span, and message for this `Session` if we're + /// not outputting in JSON mode. + // + // FIXME: if the need arises for one-time diagnostics other than + // `span_note`, we almost certainly want to generalize this + // "check/insert-into the one-time diagnostics map, then set message if + // it's not already there" code to accomodate all of them + pub fn diag_span_note_once<'a, 'b>(&'a self, + diag_builder: &'b mut DiagnosticBuilder<'a>, + lint: &'static lint::Lint, span: Span, message: &str) { + match self.opts.error_format { + // when outputting JSON for tool consumption, the tool might want + // the duplicates + config::ErrorOutputType::Json => { + diag_builder.span_note(span, &message); + }, + _ => { + let lint_id = lint::LintId::of(lint); + let id_span_message = (lint_id, span, message.to_owned()); + let fresh = self.one_time_diagnostics.borrow_mut().insert(id_span_message); + if fresh { + diag_builder.span_note(span, &message); + } + } + } + } + pub fn codemap<'a>(&'a self) -> &'a codemap::CodeMap { self.parse_sess.codemap() } @@ -306,9 +352,13 @@ impl Session { pub fn lto(&self) -> bool { self.opts.cg.lto } + /// Returns the panic strategy for this compile session. If the user explicitly selected one + /// using '-C panic', use that, otherwise use the panic strategy defined by the target. + pub fn panic_strategy(&self) -> PanicStrategy { + self.opts.cg.panic.unwrap_or(self.target.target.options.panic_strategy) + } pub fn no_landing_pads(&self) -> bool { - self.opts.debugging_opts.no_landing_pads || - self.opts.cg.panic == PanicStrategy::Abort + self.opts.debugging_opts.no_landing_pads || self.panic_strategy() == PanicStrategy::Abort } pub fn unstable_options(&self) -> bool { self.opts.debugging_opts.unstable_options @@ -433,6 +483,11 @@ impl Session { duration_to_secs_str(self.perf_stats.incr_comp_hashes_time.get())); println!("Total number of incr. comp. hashes computed: {}", self.perf_stats.incr_comp_hashes_count.get()); + println!("Total number of bytes hashed for incr. comp.: {}", + self.perf_stats.incr_comp_bytes_hashed.get()); + println!("Average bytes hashed per incr. comp. HIR node: {}", + self.perf_stats.incr_comp_bytes_hashed.get() / + self.perf_stats.incr_comp_hashes_count.get()); println!("Total time spent computing symbol hashes: {}", duration_to_secs_str(self.perf_stats.symbol_hash_time.get())); } @@ -449,7 +504,8 @@ pub fn build_session(sopts: config::Options, local_crate_source_file, registry, cstore, - Rc::new(codemap::CodeMap::new())) + Rc::new(codemap::CodeMap::new()), + None) } pub fn build_session_with_codemap(sopts: config::Options, @@ -457,7 +513,8 @@ pub fn build_session_with_codemap(sopts: config::Options, local_crate_source_file: Option, registry: errors::registry::Registry, cstore: Rc CrateStore<'a>>, - codemap: Rc) + codemap: Rc, + emitter_dest: Option>) -> Session { // FIXME: This is not general enough to make the warning lint completely override // normal diagnostic warnings, since the warning lint can also be denied and changed @@ -470,14 +527,21 @@ pub fn build_session_with_codemap(sopts: config::Options, .unwrap_or(true); let treat_err_as_bug = sopts.debugging_opts.treat_err_as_bug; - let emitter: Box = match sopts.error_format { - config::ErrorOutputType::HumanReadable(color_config) => { + let emitter: Box = match (sopts.error_format, emitter_dest) { + (config::ErrorOutputType::HumanReadable(color_config), None) => { Box::new(EmitterWriter::stderr(color_config, Some(codemap.clone()))) } - config::ErrorOutputType::Json => { + (config::ErrorOutputType::HumanReadable(_), Some(dst)) => { + Box::new(EmitterWriter::new(dst, + Some(codemap.clone()))) + } + (config::ErrorOutputType::Json, None) => { Box::new(JsonEmitter::stderr(Some(registry), codemap.clone())) } + (config::ErrorOutputType::Json, Some(dst)) => { + Box::new(JsonEmitter::new(dst, Some(registry), codemap.clone())) + } }; let diagnostic_handler = @@ -539,6 +603,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()), + one_time_diagnostics: RefCell::new(FnvHashSet()), plugin_llvm_passes: RefCell::new(Vec::new()), mir_passes: RefCell::new(mir_pass::Passes::new()), plugin_attributes: RefCell::new(Vec::new()), @@ -556,6 +621,7 @@ pub fn build_session_(sopts: config::Options, svh_time: Cell::new(Duration::from_secs(0)), incr_comp_hashes_time: Cell::new(Duration::from_secs(0)), incr_comp_hashes_count: Cell::new(0), + incr_comp_bytes_hashed: Cell::new(0), symbol_hash_time: Cell::new(Duration::from_secs(0)), } }; diff --git a/src/librustc/traits/coherence.rs b/src/librustc/traits/coherence.rs index 68c88249ec..1ccd048ced 100644 --- a/src/librustc/traits/coherence.rs +++ b/src/librustc/traits/coherence.rs @@ -14,7 +14,7 @@ use super::{SelectionContext, Obligation, ObligationCause}; use hir::def_id::{DefId, LOCAL_CRATE}; use ty::{self, Ty, TyCtxt}; -use infer::{InferCtxt, TypeOrigin}; +use infer::{InferCtxt, InferOk, TypeOrigin}; use syntax_pos::DUMMY_SP; #[derive(Copy, Clone)] @@ -55,11 +55,13 @@ fn overlap<'cx, 'gcx, 'tcx>(selcx: &mut SelectionContext<'cx, 'gcx, 'tcx>, debug!("overlap: b_impl_header={:?}", b_impl_header); // Do `a` and `b` unify? If not, no overlap. - if let Err(_) = selcx.infcx().eq_impl_headers(true, - TypeOrigin::Misc(DUMMY_SP), - &a_impl_header, - &b_impl_header) { - return None; + match selcx.infcx().eq_impl_headers(true, TypeOrigin::Misc(DUMMY_SP), &a_impl_header, + &b_impl_header) { + Ok(InferOk { obligations, .. }) => { + // FIXME(#32730) propagate obligations + assert!(obligations.is_empty()); + } + Err(_) => return None } debug!("overlap: unification check succeeded"); diff --git a/src/librustc/traits/error_reporting.rs b/src/librustc/traits/error_reporting.rs index 52ddd8ab5d..89c8162456 100644 --- a/src/librustc/traits/error_reporting.rs +++ b/src/librustc/traits/error_reporting.rs @@ -27,6 +27,7 @@ use super::{ use fmt_macros::{Parser, Piece, Position}; use hir::def_id::DefId; use infer::{self, InferCtxt, TypeOrigin}; +use rustc::lint::builtin::EXTRA_REQUIREMENT_IN_IMPL; use ty::{self, AdtKind, ToPredicate, ToPolyTraitRef, Ty, TyCtxt, TypeFoldable}; use ty::error::ExpectedFound; use ty::fast_reject; @@ -36,6 +37,7 @@ use util::nodemap::{FnvHashMap, FnvHashSet}; use std::cmp; use std::fmt; +use syntax::ast; use syntax_pos::Span; use errors::DiagnosticBuilder; @@ -417,6 +419,45 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> { self.report_overflow_error(&cycle[0], false); } + pub fn report_extra_impl_obligation(&self, + error_span: Span, + item_name: ast::Name, + _impl_item_def_id: DefId, + trait_item_def_id: DefId, + requirement: &fmt::Display, + lint_id: Option) // (*) + -> DiagnosticBuilder<'tcx> + { + // (*) This parameter is temporary and used only for phasing + // in the bug fix to #18937. If it is `Some`, it has a kind of + // weird effect -- the diagnostic is reported as a lint, and + // the builder which is returned is marked as canceled. + + let mut err = + struct_span_err!(self.tcx.sess, + error_span, + E0276, + "impl has stricter requirements than trait"); + + if let Some(trait_item_span) = self.tcx.map.span_if_local(trait_item_def_id) { + err.span_label(trait_item_span, + &format!("definition of `{}` from trait", item_name)); + } + + err.span_label( + error_span, + &format!("impl has extra requirement {}", requirement)); + + if let Some(node_id) = lint_id { + self.tcx.sess.add_lint_diagnostic(EXTRA_REQUIREMENT_IN_IMPL, + node_id, + (*err).clone()); + err.cancel(); + } + + err + } + pub fn report_selection_error(&self, obligation: &PredicateObligation<'tcx>, error: &SelectionError<'tcx>) @@ -424,12 +465,17 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> { let span = obligation.cause.span; let mut err = match *error { SelectionError::Unimplemented => { - if let ObligationCauseCode::CompareImplMethodObligation = obligation.cause.code { - span_err!( - self.tcx.sess, span, E0276, - "the requirement `{}` appears on the impl \ - method but not on the corresponding trait method", - obligation.predicate); + if let ObligationCauseCode::CompareImplMethodObligation { + item_name, impl_item_def_id, trait_item_def_id, lint_id + } = obligation.cause.code { + self.report_extra_impl_obligation( + span, + item_name, + impl_item_def_id, + trait_item_def_id, + &format!("`{}`", obligation.predicate), + lint_id) + .emit(); return; } else { match obligation.predicate { @@ -445,8 +491,10 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> { let mut err = struct_span_err!(self.tcx.sess, span, E0277, "the trait bound `{}` is not satisfied", trait_ref.to_predicate()); - err.span_label(span, &format!("trait `{}` not satisfied", - trait_ref.to_predicate())); + err.span_label(span, &format!("the trait `{}` is not implemented \ + for `{}`", + trait_ref, + trait_ref.self_ty())); // Try to report a help message @@ -490,7 +538,7 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> { ty::Predicate::RegionOutlives(ref predicate) => { let predicate = self.resolve_type_vars_if_possible(predicate); - let err = self.region_outlives_predicate(span, + let err = self.region_outlives_predicate(&obligation.cause, &predicate).err().unwrap(); struct_span_err!(self.tcx.sess, span, E0279, "the requirement `{}` is not satisfied (`{}`)", @@ -820,6 +868,11 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> { err.note(&format!("required so that reference `{}` does not outlive its referent", ref_ty)); } + ObligationCauseCode::ObjectTypeBound(object_ty, region) => { + err.note(&format!("required so that the lifetime bound of `{}` for `{}` \ + is satisfied", + region, object_ty)); + } ObligationCauseCode::ItemObligation(item_def_id) => { let item_name = tcx.item_path_str(item_def_id); err.note(&format!("required by `{}`", item_name)); @@ -856,8 +909,7 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> { trait_name)); } ObligationCauseCode::FieldSized => { - err.note("only the last field of a struct or enum variant \ - may have a dynamically sized type"); + err.note("only the last field of a struct may have a dynamically sized type"); } ObligationCauseCode::ConstSized => { err.note("constant expressions must have a statically known size"); @@ -885,7 +937,7 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> { &parent_predicate, &data.parent_code); } - ObligationCauseCode::CompareImplMethodObligation => { + ObligationCauseCode::CompareImplMethodObligation { .. } => { err.note( &format!("the requirement `{}` appears on the impl method \ but not on the corresponding trait method", diff --git a/src/librustc/traits/fulfill.rs b/src/librustc/traits/fulfill.rs index 65860671c4..906da42903 100644 --- a/src/librustc/traits/fulfill.rs +++ b/src/librustc/traits/fulfill.rs @@ -11,7 +11,7 @@ use dep_graph::DepGraph; use infer::{InferCtxt, InferOk}; use ty::{self, Ty, TypeFoldable, ToPolyTraitRef, TyCtxt, ToPredicate}; -use ty::subst::{Substs, Subst}; +use ty::subst::Subst; use rustc_data_structures::obligation_forest::{ObligationForest, Error}; use rustc_data_structures::obligation_forest::{ForestObligation, ObligationProcessor}; use std::marker::PhantomData; @@ -159,7 +159,7 @@ impl<'a, 'gcx, 'tcx> DeferredObligation<'tcx> { let concrete_ty = ty_scheme.ty.subst(tcx, substs); let predicate = ty::TraitRef { def_id: self.predicate.def_id(), - substs: Substs::new_trait(tcx, concrete_ty, &[]) + substs: tcx.mk_substs_trait(concrete_ty, &[]) }.to_predicate(); let original_obligation = Obligation::new(self.cause.clone(), @@ -526,7 +526,7 @@ fn process_predicate<'a, 'gcx, 'tcx>( } ty::Predicate::RegionOutlives(ref binder) => { - match selcx.infcx().region_outlives_predicate(obligation.cause.span, binder) { + match selcx.infcx().region_outlives_predicate(&obligation.cause, binder) { Ok(()) => Ok(Some(Vec::new())), Err(_) => Err(CodeSelectionError(Unimplemented)), } diff --git a/src/librustc/traits/mod.rs b/src/librustc/traits/mod.rs index 7ba10d9c0a..017b34d914 100644 --- a/src/librustc/traits/mod.rs +++ b/src/librustc/traits/mod.rs @@ -111,6 +111,9 @@ pub enum ObligationCauseCode<'tcx> { /// A type like `&'a T` is WF only if `T: 'a`. ReferenceOutlivesReferent(Ty<'tcx>), + /// A type like `Box + 'b>` is WF only if `'b: 'a`. + ObjectTypeBound(Ty<'tcx>, &'tcx ty::Region), + /// Obligation incurred due to an object cast. ObjectCastObligation(/* Object type */ Ty<'tcx>), @@ -138,7 +141,13 @@ pub enum ObligationCauseCode<'tcx> { ImplDerivedObligation(DerivedObligationCause<'tcx>), - CompareImplMethodObligation, + // error derived when matching traits/impls; see ObligationCause for more details + CompareImplMethodObligation { + item_name: ast::Name, + impl_item_def_id: DefId, + trait_item_def_id: DefId, + lint_id: Option, + }, } #[derive(Clone, Debug, PartialEq, Eq)] diff --git a/src/librustc/traits/project.rs b/src/librustc/traits/project.rs index ea4fc1c25a..9db9e8812f 100644 --- a/src/librustc/traits/project.rs +++ b/src/librustc/traits/project.rs @@ -167,18 +167,20 @@ pub fn poly_project_and_unify_type<'cx, 'gcx, 'tcx>( infcx.skolemize_late_bound_regions(&obligation.predicate, snapshot); let skol_obligation = obligation.with(skol_predicate); - match project_and_unify_type(selcx, &skol_obligation) { + let r = match project_and_unify_type(selcx, &skol_obligation) { Ok(result) => { let span = obligation.cause.span; match infcx.leak_check(false, span, &skol_map, snapshot) { - Ok(()) => Ok(infcx.plug_leaks(skol_map, snapshot, &result)), + Ok(()) => Ok(infcx.plug_leaks(skol_map, snapshot, result)), Err(e) => Err(MismatchedProjectionTypes { err: e }), } } Err(e) => { Err(e) } - } + }; + + r }) } @@ -273,7 +275,7 @@ impl<'a, 'b, 'gcx, 'tcx> AssociatedTypeNormalizer<'a, 'b, 'gcx, 'tcx> { AssociatedTypeNormalizer { selcx: selcx, cause: cause, - obligations: vec!(), + obligations: vec![], depth: depth, } } @@ -394,7 +396,7 @@ pub fn normalize_projection_type<'a, 'b, 'gcx, 'tcx>( cause, depth + 1, projection.to_predicate()); Normalized { value: ty_var, - obligations: vec!(obligation) + obligations: vec![obligation] } }) } @@ -543,7 +545,7 @@ fn opt_normalize_projection_type<'a, 'b, 'gcx, 'tcx>( projected_ty); let result = Normalized { value: projected_ty, - obligations: vec!() + obligations: vec![] }; infcx.projection_cache.borrow_mut() .complete(projection_ty, &result, true); @@ -602,7 +604,7 @@ fn normalize_to_error<'a, 'gcx, 'tcx>(selcx: &mut SelectionContext<'a, 'gcx, 'tc let new_value = selcx.infcx().next_ty_var(); Normalized { value: new_value, - obligations: vec!(trait_obligation) + obligations: vec![trait_obligation] } } @@ -1220,8 +1222,8 @@ fn confirm_closure_candidate<'cx, 'gcx, 'tcx>( obligation, &closure_type.sig, util::TupleArgumentsFlag::No) - .with_addl_obligations(obligations) .with_addl_obligations(vtable.nested) + .with_addl_obligations(obligations) } fn confirm_callable_candidate<'cx, 'gcx, 'tcx>( @@ -1396,6 +1398,10 @@ impl<'tcx> ProjectionCache<'tcx> { self.map.rollback_to(snapshot.snapshot); } + pub fn rollback_skolemized(&mut self, snapshot: &ProjectionCacheSnapshot) { + self.map.partial_rollback(&snapshot.snapshot, &|k| k.has_re_skol()); + } + pub fn commit(&mut self, snapshot: ProjectionCacheSnapshot) { self.map.commit(snapshot.snapshot); } @@ -1405,9 +1411,8 @@ impl<'tcx> ProjectionCache<'tcx> { /// cache hit, so it's actually a good thing). fn try_start(&mut self, key: ty::ProjectionTy<'tcx>) -> Result<(), ProjectionCacheEntry<'tcx>> { - match self.map.get(&key) { - Some(entry) => return Err(entry.clone()), - None => { } + if let Some(entry) = self.map.get(&key) { + return Err(entry.clone()); } self.map.insert(key, ProjectionCacheEntry::InProgress); diff --git a/src/librustc/traits/select.rs b/src/librustc/traits/select.rs index 05b4c44580..e75c8bd433 100644 --- a/src/librustc/traits/select.rs +++ b/src/librustc/traits/select.rs @@ -788,14 +788,11 @@ impl<'cx, 'gcx, 'tcx> SelectionContext<'cx, 'gcx, 'tcx> { stack); assert!(!stack.obligation.predicate.has_escaping_regions()); - match self.check_candidate_cache(&cache_fresh_trait_pred) { - Some(c) => { - debug!("CACHE HIT: SELECT({:?})={:?}", - cache_fresh_trait_pred, - c); - return c; - } - None => { } + if let Some(c) = self.check_candidate_cache(&cache_fresh_trait_pred) { + debug!("CACHE HIT: SELECT({:?})={:?}", + cache_fresh_trait_pred, + c); + return c; } // If no match, compute result and insert into cache. @@ -1617,7 +1614,7 @@ impl<'cx, 'gcx, 'tcx> SelectionContext<'cx, 'gcx, 'tcx> { // // We always upcast when we can because of reason // #2 (region bounds). - data_a.principal.def_id() == data_a.principal.def_id() && + data_a.principal.def_id() == data_b.principal.def_id() && data_a.builtin_bounds.is_superset(&data_b.builtin_bounds) } @@ -1980,7 +1977,7 @@ impl<'cx, 'gcx, 'tcx> SelectionContext<'cx, 'gcx, 'tcx> { normalized_ty, &[]); obligations.push(skol_obligation); - this.infcx().plug_leaks(skol_map, snapshot, &obligations) + this.infcx().plug_leaks(skol_map, snapshot, obligations) }) }).collect() } @@ -2599,7 +2596,7 @@ impl<'cx, 'gcx, 'tcx> SelectionContext<'cx, 'gcx, 'tcx> { k } }); - let substs = Substs::new(tcx, params); + let substs = tcx.mk_substs(params); for &ty in fields.split_last().unwrap().1 { if ty.subst(tcx, substs).references_error() { return Err(Unimplemented); @@ -2619,7 +2616,7 @@ impl<'cx, 'gcx, 'tcx> SelectionContext<'cx, 'gcx, 'tcx> { k } }); - let new_struct = tcx.mk_adt(def, Substs::new(tcx, params)); + let new_struct = tcx.mk_adt(def, tcx.mk_substs(params)); let origin = TypeOrigin::Misc(obligation.cause.span); let InferOk { obligations, .. } = self.infcx.sub_types(false, origin, new_struct, target) @@ -2899,7 +2896,7 @@ impl<'cx, 'gcx, 'tcx> SelectionContext<'cx, 'gcx, 'tcx> { predicate: predicate.value })) }).collect(); - self.infcx().plug_leaks(skol_map, snapshot, &predicates) + self.infcx().plug_leaks(skol_map, snapshot, predicates) } } diff --git a/src/librustc/traits/specialize/mod.rs b/src/librustc/traits/specialize/mod.rs index e281a4a99b..909247d1cb 100644 --- a/src/librustc/traits/specialize/mod.rs +++ b/src/librustc/traits/specialize/mod.rs @@ -22,10 +22,10 @@ use super::util::impl_trait_ref_and_oblig; use rustc_data_structures::fnv::FnvHashMap; use hir::def_id::DefId; -use infer::{InferCtxt, TypeOrigin}; +use infer::{InferCtxt, InferOk, TypeOrigin}; use middle::region; use ty::subst::{Subst, Substs}; -use traits::{self, Reveal, ObligationCause, Normalized}; +use traits::{self, Reveal, ObligationCause}; use ty::{self, TyCtxt, TypeFoldable}; use syntax_pos::DUMMY_SP; @@ -187,22 +187,16 @@ pub fn specializes<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, .subst(tcx, &penv.free_substs); // Create a infcx, taking the predicates of impl1 as assumptions: - let result = tcx.infer_ctxt(None, Some(penv), Reveal::ExactMatch).enter(|mut infcx| { - // Normalize the trait reference, adding any obligations - // that arise into the impl1 assumptions. - let Normalized { value: impl1_trait_ref, obligations: normalization_obligations } = { - let selcx = &mut SelectionContext::new(&infcx); - traits::normalize(selcx, ObligationCause::dummy(), &impl1_trait_ref) - }; - infcx.parameter_environment.caller_bounds - .extend(normalization_obligations.into_iter().map(|o| { - match tcx.lift_to_global(&o.predicate) { - Some(predicate) => predicate, - None => { - bug!("specializes: obligation `{:?}` has inference types/regions", o); + let result = tcx.infer_ctxt(None, Some(penv), Reveal::ExactMatch).enter(|infcx| { + // Normalize the trait reference. The WF rules ought to ensure + // that this always succeeds. + let impl1_trait_ref = + match traits::fully_normalize(&infcx, ObligationCause::dummy(), &impl1_trait_ref) { + Ok(impl1_trait_ref) => impl1_trait_ref, + Err(err) => { + bug!("failed to fully normalize {:?}: {:?}", impl1_trait_ref, err); } - } - })); + }; // Attempt to prove that impl2 applies, given all of the above. fulfill_implication(&infcx, impl1_trait_ref, impl2_def_id).is_ok() @@ -228,14 +222,18 @@ fn fulfill_implication<'a, 'gcx, 'tcx>(infcx: &InferCtxt<'a, 'gcx, 'tcx>, target_substs); // do the impls unify? If not, no specialization. - if let Err(_) = infcx.eq_trait_refs(true, - TypeOrigin::Misc(DUMMY_SP), - source_trait_ref, - target_trait_ref) { - debug!("fulfill_implication: {:?} does not unify with {:?}", - source_trait_ref, - target_trait_ref); - return Err(()); + match infcx.eq_trait_refs(true, TypeOrigin::Misc(DUMMY_SP), source_trait_ref, + target_trait_ref) { + Ok(InferOk { obligations, .. }) => { + // FIXME(#32730) propagate obligations + assert!(obligations.is_empty()) + } + Err(_) => { + debug!("fulfill_implication: {:?} does not unify with {:?}", + source_trait_ref, + target_trait_ref); + return Err(()); + } } // attempt to prove all of the predicates for impl2 given those for impl1 diff --git a/src/librustc/traits/structural_impls.rs b/src/librustc/traits/structural_impls.rs index 022566642f..d33e8b5675 100644 --- a/src/librustc/traits/structural_impls.rs +++ b/src/librustc/traits/structural_impls.rs @@ -175,6 +175,13 @@ impl<'a, 'tcx> Lift<'tcx> for traits::ObligationCauseCode<'a> { super::ReferenceOutlivesReferent(ty) => { tcx.lift(&ty).map(super::ReferenceOutlivesReferent) } + super::ObjectTypeBound(ty, r) => { + tcx.lift(&ty).and_then(|ty| { + tcx.lift(&r).and_then(|r| { + Some(super::ObjectTypeBound(ty, r)) + }) + }) + } super::ObjectCastObligation(ty) => { tcx.lift(&ty).map(super::ObjectCastObligation) } @@ -195,8 +202,16 @@ impl<'a, 'tcx> Lift<'tcx> for traits::ObligationCauseCode<'a> { super::ImplDerivedObligation(ref cause) => { tcx.lift(cause).map(super::ImplDerivedObligation) } - super::CompareImplMethodObligation => { - Some(super::CompareImplMethodObligation) + super::CompareImplMethodObligation { item_name, + impl_item_def_id, + trait_item_def_id, + lint_id } => { + Some(super::CompareImplMethodObligation { + item_name: item_name, + impl_item_def_id: impl_item_def_id, + trait_item_def_id: trait_item_def_id, + lint_id: lint_id, + }) } } } @@ -459,12 +474,15 @@ impl<'tcx> TypeFoldable<'tcx> for traits::ObligationCauseCode<'tcx> { super::FieldSized | super::ConstSized | super::SharedStatic | - super::CompareImplMethodObligation => self.clone(), + super::CompareImplMethodObligation { .. } => self.clone(), super::ProjectionWf(proj) => super::ProjectionWf(proj.fold_with(folder)), super::ReferenceOutlivesReferent(ty) => { super::ReferenceOutlivesReferent(ty.fold_with(folder)) } + super::ObjectTypeBound(ty, r) => { + super::ObjectTypeBound(ty.fold_with(folder), r.fold_with(folder)) + } super::ObjectCastObligation(ty) => { super::ObjectCastObligation(ty.fold_with(folder)) } @@ -492,10 +510,11 @@ impl<'tcx> TypeFoldable<'tcx> for traits::ObligationCauseCode<'tcx> { super::FieldSized | super::ConstSized | super::SharedStatic | - super::CompareImplMethodObligation => false, + super::CompareImplMethodObligation { .. } => false, super::ProjectionWf(proj) => proj.visit_with(visitor), super::ReferenceOutlivesReferent(ty) => ty.visit_with(visitor), + super::ObjectTypeBound(ty, r) => ty.visit_with(visitor) || r.visit_with(visitor), super::ObjectCastObligation(ty) => ty.visit_with(visitor), super::BuiltinDerivedObligation(ref cause) => cause.visit_with(visitor), super::ImplDerivedObligation(ref cause) => cause.visit_with(visitor) diff --git a/src/librustc/traits/util.rs b/src/librustc/traits/util.rs index 2cefc2ad79..a3d974216b 100644 --- a/src/librustc/traits/util.rs +++ b/src/librustc/traits/util.rs @@ -11,6 +11,7 @@ use hir::def_id::DefId; use ty::subst::{Subst, Substs}; use ty::{self, Ty, TyCtxt, ToPredicate, ToPolyTraitRef}; +use ty::outlives::Component; use util::common::ErrorReported; use util::nodemap::FnvHashSet; @@ -166,27 +167,63 @@ impl<'cx, 'gcx, 'tcx> Elaborator<'cx, 'gcx, 'tcx> { ty::Predicate::ClosureKind(..) => { // Nothing to elaborate when waiting for a closure's kind to be inferred. } - ty::Predicate::RegionOutlives(..) | - ty::Predicate::TypeOutlives(..) => { - // Currently, we do not "elaborate" predicates like - // `'a : 'b` or `T : 'a`. We could conceivably do - // more here. For example, - // - // &'a int : 'b - // - // implies that - // - // 'a : 'b - // - // and we could get even more if we took WF - // constraints into account. For example, - // - // &'a &'b int : 'c - // - // implies that + + ty::Predicate::RegionOutlives(..) => { + // Nothing to elaborate from `'a: 'b`. + } + + ty::Predicate::TypeOutlives(ref data) => { + // We know that `T: 'a` for some type `T`. We can + // often elaborate this. For example, if we know that + // `[U]: 'a`, that implies that `U: 'a`. Similarly, if + // we know `&'a U: 'b`, then we know that `'a: 'b` and + // `U: 'b`. // - // 'b : 'a - // 'a : 'c + // We can basically ignore bound regions here. So for + // example `for<'c> Foo<'a,'c>: 'b` can be elaborated to + // `'a: 'b`. + + // Ignore `for<'a> T: 'a` -- we might in the future + // consider this as evidence that `T: 'static`, but + // I'm a bit wary of such constructions and so for now + // I want to be conservative. --nmatsakis + let ty_max = data.skip_binder().0; + let r_min = data.skip_binder().1; + if r_min.is_bound() { + return; + } + + let visited = &mut self.visited; + self.stack.extend( + tcx.outlives_components(ty_max) + .into_iter() + .filter_map(|component| match component { + Component::Region(r) => if r.is_bound() { + None + } else { + Some(ty::Predicate::RegionOutlives( + ty::Binder(ty::OutlivesPredicate(r, r_min)))) + }, + + Component::Param(p) => { + let ty = tcx.mk_param(p.idx, p.name); + Some(ty::Predicate::TypeOutlives( + ty::Binder(ty::OutlivesPredicate(ty, r_min)))) + }, + + Component::UnresolvedInferenceVariable(_) => { + None + }, + + Component::Projection(_) | + Component::EscapingProjection(_) => { + // We can probably do more here. This + // corresponds to a case like `>::U: 'b`. + None + }, + }) + .filter(|p| visited.insert(p))); } } } @@ -380,7 +417,7 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> { Ok(def_id) => { Ok(ty::TraitRef { def_id: def_id, - substs: Substs::new_trait(self, param_ty, &[]) + substs: self.mk_substs_trait(param_ty, &[]) }) } Err(e) => { @@ -400,7 +437,7 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> { { let trait_ref = ty::TraitRef { def_id: trait_def_id, - substs: Substs::new_trait(self, param_ty, ty_params) + substs: self.mk_substs_trait(param_ty, ty_params) }; predicate_for_trait_ref(cause, trait_ref, recursion_depth) } @@ -486,11 +523,11 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> { { let arguments_tuple = match tuple_arguments { TupleArgumentsFlag::No => sig.0.inputs[0], - TupleArgumentsFlag::Yes => self.mk_tup(sig.0.inputs.to_vec()), + TupleArgumentsFlag::Yes => self.intern_tup(&sig.0.inputs[..]), }; let trait_ref = ty::TraitRef { def_id: fn_trait_def_id, - substs: Substs::new_trait(self, self_ty, &[arguments_tuple]), + substs: self.mk_substs_trait(self_ty, &[arguments_tuple]), }; ty::Binder((trait_ref, sig.0.output)) } diff --git a/src/librustc/ty/adjustment.rs b/src/librustc/ty/adjustment.rs index cfe370343a..333a5c74cb 100644 --- a/src/librustc/ty/adjustment.rs +++ b/src/librustc/ty/adjustment.rs @@ -8,10 +8,7 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -pub use self::AutoAdjustment::*; -pub use self::AutoRef::*; - -use ty::{self, Ty, TyCtxt, TypeAndMut, TypeFoldable}; +use ty::{self, Ty, TyCtxt, TypeAndMut}; use ty::LvaluePreference::{NoPreference}; use syntax::ast; @@ -20,116 +17,122 @@ use syntax_pos::Span; use hir; #[derive(Copy, Clone, RustcEncodable, RustcDecodable)] -pub enum AutoAdjustment<'tcx> { - AdjustNeverToAny(Ty<'tcx>), // go from ! to any type - AdjustReifyFnPointer, // go from a fn-item type to a fn-pointer type - AdjustUnsafeFnPointer, // go from a safe fn pointer to an unsafe fn pointer - AdjustMutToConstPointer, // go from a mut raw pointer to a const raw pointer - AdjustDerefRef(AutoDerefRef<'tcx>), +pub struct Adjustment<'tcx> { + pub kind: Adjust<'tcx>, + pub target: Ty<'tcx> } -/// 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 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, RustcEncodable, RustcDecodable)] -pub struct AutoDerefRef<'tcx> { - /// Step 1. Apply a number of dereferences, producing an lvalue. - pub autoderefs: usize, - - /// Step 2. Optionally produce a pointer/reference from the value. - pub autoref: Option>, - - /// 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>, +#[derive(Copy, Clone, Debug, RustcEncodable, RustcDecodable)] +pub enum Adjust<'tcx> { + /// Go from ! to any type. + NeverToAny, + + /// Go from a fn-item type to a fn-pointer type. + ReifyFnPointer, + + /// Go from a safe fn pointer to an unsafe fn pointer. + UnsafeFnPointer, + + /// Go from a mut raw pointer to a const raw pointer. + MutToConstPointer, + + /// 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 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: + /// + /// ``` + /// Adjust::DerefRef { + /// autoderefs: 1, // &[i32; 4] -> [i32; 4] + /// autoref: Some(AutoBorrow::Ref), // [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: + /// + /// ``` + /// Adjust::DerefRef { + /// autoderefs: 0, + /// autoref: None, + /// unsize: Some(Box<[i32]>), + /// } + /// ``` + DerefRef { + /// Step 1. Apply a number of dereferences, producing an lvalue. + autoderefs: usize, + + /// Step 2. Optionally produce a pointer/reference from the value. + autoref: Option>, + + /// Step 3. Unsize a pointer/reference value, e.g. `&[T; n]` to + /// `&[T]`. Note that the source could be a thin or fat pointer. + unsize: bool, + } } -impl<'tcx> AutoAdjustment<'tcx> { +impl<'tcx> Adjustment<'tcx> { pub fn is_identity(&self) -> bool { - match *self { - AdjustNeverToAny(ty) => ty.is_never(), - AdjustReifyFnPointer | - AdjustUnsafeFnPointer | - AdjustMutToConstPointer => false, - AdjustDerefRef(ref r) => r.is_identity(), + match self.kind { + Adjust::NeverToAny => self.target.is_never(), + + Adjust::DerefRef { autoderefs: 0, autoref: None, unsize: false } => true, + + Adjust::ReifyFnPointer | + Adjust::UnsafeFnPointer | + Adjust::MutToConstPointer | + Adjust::DerefRef {..} => false, } } } -impl<'tcx> AutoDerefRef<'tcx> { - pub fn is_identity(&self) -> bool { - self.autoderefs == 0 && self.unsize.is_none() && self.autoref.is_none() - } -} - #[derive(Copy, Clone, PartialEq, Debug, RustcEncodable, RustcDecodable)] -pub enum AutoRef<'tcx> { +pub enum AutoBorrow<'tcx> { /// Convert from T to &T. - AutoPtr(&'tcx ty::Region, hir::Mutability), + Ref(&'tcx ty::Region, hir::Mutability), /// Convert from T to *T. - /// Value to thin pointer. - AutoUnsafe(hir::Mutability), + RawPtr(hir::Mutability), } #[derive(Clone, Copy, RustcEncodable, RustcDecodable, Debug)] @@ -139,84 +142,6 @@ pub enum CustomCoerceUnsized { } impl<'a, 'gcx, 'tcx> ty::TyS<'tcx> { - /// See `expr_ty_adjusted` - pub fn adjust(&'tcx self, - tcx: TyCtxt<'a, 'gcx, 'tcx>, - span: Span, - expr_id: ast::NodeId, - adjustment: Option<&AutoAdjustment<'tcx>>, - mut method_type: F) - -> Ty<'tcx> where - F: FnMut(ty::MethodCall) -> Option>, - { - if let ty::TyError = self.sty { - return self; - } - - return match adjustment { - Some(adjustment) => { - match *adjustment { - AdjustNeverToAny(ref ty) => ty, - - AdjustReifyFnPointer => { - match self.sty { - ty::TyFnDef(.., f) => tcx.mk_fn_ptr(f), - _ => { - bug!("AdjustReifyFnPointer adjustment on non-fn-item: {:?}", - self); - } - } - } - - AdjustUnsafeFnPointer => { - match self.sty { - ty::TyFnPtr(b) => tcx.safe_to_unsafe_fn_ty(b), - ref b => { - bug!("AdjustUnsafeFnPointer adjustment on non-fn-ptr: {:?}", - b); - } - } - } - - AdjustMutToConstPointer => { - match self.sty { - ty::TyRawPtr(mt) => tcx.mk_ptr(ty::TypeAndMut { - ty: mt.ty, - mutbl: hir::MutImmutable - }), - ref b => { - bug!("AdjustMutToConstPointer on non-raw-ptr: {:?}", - b); - } - } - } - - AdjustDerefRef(ref adj) => { - let mut adjusted_ty = self; - - if !adjusted_ty.references_error() { - for i in 0..adj.autoderefs { - adjusted_ty = - adjusted_ty.adjust_for_autoderef(tcx, - expr_id, - span, - i as u32, - &mut method_type); - } - } - - if let Some(target) = adj.unsize { - target - } else { - adjusted_ty.adjust_for_autoref(tcx, adj.autoref) - } - } - } - } - None => self - }; - } - pub fn adjust_for_autoderef(&'tcx self, tcx: TyCtxt<'a, 'gcx, 'tcx>, expr_id: ast::NodeId, @@ -247,14 +172,14 @@ impl<'a, 'gcx, 'tcx> ty::TyS<'tcx> { } pub fn adjust_for_autoref(&'tcx self, tcx: TyCtxt<'a, 'gcx, 'tcx>, - autoref: Option>) + autoref: Option>) -> Ty<'tcx> { match autoref { None => self, - Some(AutoPtr(r, m)) => { + Some(AutoBorrow::Ref(r, m)) => { tcx.mk_ref(r, TypeAndMut { ty: self, mutbl: m }) } - Some(AutoUnsafe(m)) => { + Some(AutoBorrow::RawPtr(m)) => { tcx.mk_ptr(TypeAndMut { ty: self, mutbl: m }) } } diff --git a/src/librustc/ty/context.rs b/src/librustc/ty/context.rs index 0c7c387b67..7e5e10435d 100644 --- a/src/librustc/ty/context.rs +++ b/src/librustc/ty/context.rs @@ -17,12 +17,13 @@ use hir::TraitMap; use hir::def::DefMap; use hir::def_id::{CrateNum, DefId, DefIndex, LOCAL_CRATE}; use hir::map as ast_map; -use hir::map::{DefKey, DefPath, DefPathData, DisambiguatedDefPathData}; +use hir::map::{DefKey, DefPathData, DisambiguatedDefPathData}; use middle::free_region::FreeRegionMap; use middle::region::RegionMaps; use middle::resolve_lifetime; use middle::stability; -use ty::subst::Substs; +use mir::Mir; +use ty::subst::{Kind, Substs}; use traits; use ty::{self, TraitRef, Ty, TypeAndMut}; use ty::{TyS, TypeVariants, Slice}; @@ -36,14 +37,16 @@ use ty::maps; use util::common::MemoizationMap; use util::nodemap::{NodeMap, NodeSet, DefIdMap, DefIdSet}; use util::nodemap::{FnvHashMap, FnvHashSet}; +use rustc_data_structures::accumulate_vec::AccumulateVec; use arena::TypedArena; use std::borrow::Borrow; -use std::cell::{Cell, RefCell, Ref}; +use std::cell::{Cell, RefCell}; use std::hash::{Hash, Hasher}; use std::mem; use std::ops::Deref; use std::rc::Rc; +use std::iter; use syntax::ast::{self, Name, NodeId}; use syntax::attr; use syntax::parse::token::{self, keywords}; @@ -54,8 +57,8 @@ use hir; pub struct CtxtArenas<'tcx> { // internings type_: TypedArena>, - type_list: TypedArena>>, - substs: TypedArena>, + type_list: TypedArena>, + substs: TypedArena>, bare_fn: TypedArena>, region: TypedArena, stability: TypedArena, @@ -63,8 +66,9 @@ pub struct CtxtArenas<'tcx> { // references generics: TypedArena>, - trait_defs: TypedArena>, - adt_defs: TypedArena>, + trait_def: TypedArena>, + adt_def: TypedArena>, + mir: TypedArena>>, } impl<'tcx> CtxtArenas<'tcx> { @@ -79,8 +83,9 @@ impl<'tcx> CtxtArenas<'tcx> { layout: TypedArena::new(), generics: TypedArena::new(), - trait_defs: TypedArena::new(), - adt_defs: TypedArena::new() + trait_def: TypedArena::new(), + adt_def: TypedArena::new(), + mir: TypedArena::new() } } } @@ -207,7 +212,7 @@ pub struct Tables<'tcx> { /// other items. pub item_substs: NodeMap>, - pub adjustments: NodeMap>, + pub adjustments: NodeMap>, pub method_map: ty::MethodMap<'tcx>, @@ -250,6 +255,76 @@ impl<'a, 'gcx, 'tcx> Tables<'tcx> { fru_field_types: NodeMap() } } + + pub fn node_id_to_type(&self, id: NodeId) -> Ty<'tcx> { + match self.node_id_to_type_opt(id) { + Some(ty) => ty, + None => { + bug!("node_id_to_type: no type for node `{}`", + tls::with(|tcx| tcx.map.node_to_string(id))) + } + } + } + + pub fn node_id_to_type_opt(&self, id: NodeId) -> Option> { + self.node_types.get(&id).cloned() + } + + pub fn node_id_item_substs(&self, id: NodeId) -> Option<&'tcx Substs<'tcx>> { + self.item_substs.get(&id).map(|ts| ts.substs) + } + + // Returns the type of a pattern as a monotype. Like @expr_ty, this function + // doesn't provide type parameter substitutions. + pub fn pat_ty(&self, pat: &hir::Pat) -> Ty<'tcx> { + self.node_id_to_type(pat.id) + } + + pub fn pat_ty_opt(&self, pat: &hir::Pat) -> Option> { + self.node_id_to_type_opt(pat.id) + } + + // Returns the type of an expression as a monotype. + // + // NB (1): This is the PRE-ADJUSTMENT TYPE for the expression. That is, in + // some cases, we insert `Adjustment` annotations such as auto-deref or + // auto-ref. The type returned by this function does not consider such + // adjustments. See `expr_ty_adjusted()` instead. + // + // NB (2): This type doesn't provide type parameter substitutions; e.g. if you + // ask for the type of "id" in "id(3)", it will return "fn(&isize) -> isize" + // instead of "fn(ty) -> T with T = isize". + pub fn expr_ty(&self, expr: &hir::Expr) -> Ty<'tcx> { + self.node_id_to_type(expr.id) + } + + pub fn expr_ty_opt(&self, expr: &hir::Expr) -> Option> { + self.node_id_to_type_opt(expr.id) + } + + /// Returns the type of `expr`, considering any `Adjustment` + /// entry recorded for that expression. + pub fn expr_ty_adjusted(&self, expr: &hir::Expr) -> Ty<'tcx> { + self.adjustments.get(&expr.id) + .map_or_else(|| self.expr_ty(expr), |adj| adj.target) + } + + pub fn expr_ty_adjusted_opt(&self, expr: &hir::Expr) -> Option> { + self.adjustments.get(&expr.id) + .map(|adj| adj.target).or_else(|| self.expr_ty_opt(expr)) + } + + pub fn is_method_call(&self, expr_id: NodeId) -> bool { + self.method_map.contains_key(&ty::MethodCall::expr(expr_id)) + } + + pub fn is_overloaded_autoderef(&self, expr_id: NodeId, autoderefs: u32) -> bool { + self.method_map.contains_key(&ty::MethodCall::autoderef(expr_id, autoderefs)) + } + + pub fn upvar_capture(&self, upvar_id: ty::UpvarId) -> Option> { + Some(self.upvar_capture_map.get(&upvar_id).unwrap().clone()) + } } impl<'tcx> CommonTypes<'tcx> { @@ -356,6 +431,15 @@ pub struct GlobalCtxt<'tcx> { pub map: ast_map::Map<'tcx>, + /// Maps from the def-id of a function/method or const/static + /// to its MIR. Mutation is done at an item granularity to + /// allow MIR optimization passes to function and still + /// access cross-crate MIR (e.g. inlining or const eval). + /// + /// Note that cross-crate MIR appears to be always borrowed + /// (in the `RefCell` sense) to prevent accidental mutation. + pub mir_map: RefCell>>, + // Records the free variables refrenced by every closure // expression. Do not track deps for this, just recompute it from // scratch every time. @@ -493,7 +577,7 @@ pub struct GlobalCtxt<'tcx> { pub layout_depth: Cell, /// Map from function to the `#[derive]` mode that it's defining. Only used - /// by `rustc-macro` crates. + /// by `proc-macro` crates. pub derive_macros: RefCell>, } @@ -546,8 +630,11 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> { } } - pub fn retrace_path(self, path: &DefPath) -> Option { - debug!("retrace_path(path={:?}, krate={:?})", path, self.crate_name(path.krate)); + pub fn retrace_path(self, + krate: CrateNum, + path_data: &[DisambiguatedDefPathData]) + -> Option { + debug!("retrace_path(path={:?}, krate={:?})", path_data, self.crate_name(krate)); let root_key = DefKey { parent: None, @@ -557,22 +644,22 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> { }, }; - let root_index = self.def_index_for_def_key(path.krate, root_key) + let root_index = self.def_index_for_def_key(krate, root_key) .expect("no root key?"); debug!("retrace_path: root_index={:?}", root_index); let mut index = root_index; - for data in &path.data { + for data in path_data { let key = DefKey { parent: Some(index), disambiguated_data: data.clone() }; debug!("retrace_path: key={:?}", key); - match self.def_index_for_def_key(path.krate, key) { + match self.def_index_for_def_key(krate, key) { Some(i) => index = i, None => return None, } } - Some(DefId { krate: path.krate, index: index }) + Some(DefId { krate: krate, index: index }) } pub fn type_parameter_def(self, @@ -582,14 +669,6 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> { self.ty_param_defs.borrow().get(&node_id).unwrap().clone() } - pub fn node_types(self) -> Ref<'a, NodeMap>> { - fn projection<'a, 'tcx>(tables: &'a Tables<'tcx>) -> &'a NodeMap> { - &tables.node_types - } - - Ref::map(self.tables.borrow(), projection) - } - pub fn node_type_insert(self, id: NodeId, ty: Ty<'gcx>) { self.tables.borrow_mut().node_types.insert(id, ty); } @@ -599,6 +678,10 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> { self.global_interners.arenas.generics.alloc(generics) } + pub fn alloc_mir(self, mir: Mir<'gcx>) -> &'gcx RefCell> { + self.global_interners.arenas.mir.alloc(RefCell::new(mir)) + } + pub fn intern_trait_def(self, def: ty::TraitDef<'gcx>) -> &'gcx ty::TraitDef<'gcx> { let did = def.trait_ref.def_id; @@ -612,7 +695,7 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> { pub fn alloc_trait_def(self, def: ty::TraitDef<'gcx>) -> &'gcx ty::TraitDef<'gcx> { - self.global_interners.arenas.trait_defs.alloc(def) + self.global_interners.arenas.trait_def.alloc(def) } pub fn insert_adt_def(self, did: DefId, adt_def: ty::AdtDefMaster<'gcx>) { @@ -628,7 +711,7 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> { variants: Vec>) -> ty::AdtDefMaster<'gcx> { let def = ty::AdtDefData::new(self, did, kind, variants); - let interned = self.global_interners.arenas.adt_defs.alloc(def); + let interned = self.global_interners.arenas.adt_def.alloc(def); self.insert_adt_def(did, interned); interned } @@ -733,6 +816,7 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> { super_predicates: RefCell::new(DepTrackingMap::new(dep_graph.clone())), fulfilled_predicates: RefCell::new(fulfilled_predicates), map: map, + mir_map: RefCell::new(DepTrackingMap::new(dep_graph.clone())), freevars: RefCell::new(freevars), maybe_unused_trait_imports: maybe_unused_trait_imports, tcache: RefCell::new(DepTrackingMap::new(dep_graph.clone())), @@ -821,7 +905,10 @@ impl<'a, 'tcx> Lift<'tcx> for Ty<'a> { impl<'a, 'tcx> Lift<'tcx> for &'a Substs<'a> { type Lifted = &'tcx Substs<'tcx>; fn lift_to_tcx<'b, 'gcx>(&self, tcx: TyCtxt<'b, 'gcx, 'tcx>) -> Option<&'tcx Substs<'tcx>> { - if let Some(&Interned(substs)) = tcx.interners.substs.borrow().get(*self) { + if self.len() == 0 { + return Some(Slice::empty()); + } + if let Some(&Interned(substs)) = tcx.interners.substs.borrow().get(&self[..]) { if *self as *const _ == substs as *const _ { return Some(substs); } @@ -856,6 +943,9 @@ impl<'a, 'tcx> Lift<'tcx> for &'a Slice> { type Lifted = &'tcx Slice>; fn lift_to_tcx<'b, 'gcx>(&self, tcx: TyCtxt<'b, 'gcx, 'tcx>) -> Option<&'tcx Slice>> { + if self.len() == 0 { + return Some(Slice::empty()); + } if let Some(&Interned(list)) = tcx.interners.type_list.borrow().get(&self[..]) { if *self as *const _ == list as *const _ { return Some(list); @@ -1094,9 +1184,9 @@ impl<'tcx: 'lcx, 'lcx> Borrow<[Ty<'lcx>]> for Interned<'tcx, Slice>> { } } -impl<'tcx: 'lcx, 'lcx> Borrow> for Interned<'tcx, Substs<'tcx>> { - fn borrow<'a>(&'a self) -> &'a Substs<'lcx> { - self.0 +impl<'tcx: 'lcx, 'lcx> Borrow<[Kind<'lcx>]> for Interned<'tcx, Substs<'tcx>> { + fn borrow<'a>(&'a self) -> &'a [Kind<'lcx>] { + &self.0[..] } } @@ -1114,6 +1204,7 @@ impl<'tcx> Borrow for Interned<'tcx, Region> { macro_rules! intern_method { ($lt_tcx:tt, $name:ident: $method:ident($alloc:ty, + $alloc_method:ident, $alloc_to_key:expr, $alloc_to_ret:expr, $needs_infer:expr) -> $ty:ty) => { @@ -1139,7 +1230,8 @@ macro_rules! intern_method { let v = unsafe { mem::transmute(v) }; - let i = ($alloc_to_ret)(self.global_interners.arenas.$name.alloc(v)); + let i = ($alloc_to_ret)(self.global_interners.arenas.$name + .$alloc_method(v)); self.global_interners.$name.borrow_mut().insert(Interned(i)); return i; } @@ -1153,7 +1245,7 @@ macro_rules! intern_method { } } - let i = ($alloc_to_ret)(self.interners.arenas.$name.alloc(v)); + let i = ($alloc_to_ret)(self.interners.arenas.$name.$alloc_method(v)); self.interners.$name.borrow_mut().insert(Interned(i)); i } @@ -1177,7 +1269,7 @@ macro_rules! direct_interners { } } - intern_method!($lt_tcx, $name: $method($ty, |x| x, |x| x, $needs_infer) -> $ty);)+ + intern_method!($lt_tcx, $name: $method($ty, alloc, |x| x, |x| x, $needs_infer) -> $ty);)+ } } @@ -1186,9 +1278,6 @@ fn keep_local<'tcx, T: ty::TypeFoldable<'tcx>>(x: &T) -> bool { } direct_interners!('tcx, - substs: mk_substs(|substs: &Substs| { - substs.params().iter().any(keep_local) - }) -> Substs<'tcx>, bare_fn: mk_bare_fn(|fty: &BareFnTy| { keep_local(&fty.sig) }) -> BareFnTy<'tcx>, @@ -1200,10 +1289,18 @@ direct_interners!('tcx, }) -> Region ); -intern_method!('tcx, - type_list: mk_type_list(Vec>, Deref::deref, |xs: &[Ty]| -> &Slice { - unsafe { mem::transmute(xs) } - }, keep_local) -> Slice> +macro_rules! slice_interners { + ($($field:ident: $method:ident($ty:ident)),+) => ( + $(intern_method!('tcx, $field: $method(&[$ty<'tcx>], alloc_slice, Deref::deref, + |xs: &[$ty]| -> &Slice<$ty> { + unsafe { mem::transmute(xs) } + }, |xs: &[$ty]| xs.iter().any(keep_local)) -> Slice<$ty<'tcx>>);)+ + ) +} + +slice_interners!( + type_list: _intern_type_list(Ty), + substs: _intern_substs(Kind) ); impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> { @@ -1308,12 +1405,16 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> { self.mk_ty(TySlice(ty)) } - pub fn mk_tup(self, ts: Vec>) -> Ty<'tcx> { - self.mk_ty(TyTuple(self.mk_type_list(ts))) + pub fn intern_tup(self, ts: &[Ty<'tcx>]) -> Ty<'tcx> { + self.mk_ty(TyTuple(self.intern_type_list(ts))) + } + + pub fn mk_tup], Ty<'tcx>>>(self, iter: I) -> I::Output { + iter.intern_with(|ts| self.mk_ty(TyTuple(self.intern_type_list(ts)))) } pub fn mk_nil(self) -> Ty<'tcx> { - self.mk_tup(Vec::new()) + self.intern_tup(&[]) } pub fn mk_diverging_default(self) -> Ty<'tcx> { @@ -1355,11 +1456,11 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> { pub fn mk_closure(self, closure_id: DefId, substs: &'tcx Substs<'tcx>, - tys: Vec>) + tys: &[Ty<'tcx>]) -> Ty<'tcx> { self.mk_closure_from_closure_substs(closure_id, ClosureSubsts { func_substs: substs, - upvar_tys: self.mk_type_list(tys) + upvar_tys: self.intern_type_list(tys) }) } @@ -1404,6 +1505,40 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> { self.mk_ty(TyAnon(def_id, substs)) } + pub fn intern_type_list(self, ts: &[Ty<'tcx>]) -> &'tcx Slice> { + if ts.len() == 0 { + Slice::empty() + } else { + self._intern_type_list(ts) + } + } + + pub fn intern_substs(self, ts: &[Kind<'tcx>]) -> &'tcx Slice> { + if ts.len() == 0 { + Slice::empty() + } else { + self._intern_substs(ts) + } + } + + pub fn mk_type_list], + &'tcx Slice>>>(self, iter: I) -> I::Output { + iter.intern_with(|xs| self.intern_type_list(xs)) + } + + pub fn mk_substs], + &'tcx Slice>>>(self, iter: I) -> I::Output { + iter.intern_with(|xs| self.intern_substs(xs)) + } + + pub fn mk_substs_trait(self, + s: Ty<'tcx>, + t: &[Ty<'tcx>]) + -> &'tcx Substs<'tcx> + { + self.mk_substs(iter::once(s).chain(t.into_iter().cloned()).map(Kind::from)) + } + pub fn trait_items(self, trait_did: DefId) -> Rc>> { self.trait_items_cache.memoize(trait_did, || { let def_ids = self.impl_or_trait_items(trait_did); @@ -1422,3 +1557,39 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> { }) } } + +pub trait InternAs { + type Output; + fn intern_with(self, F) -> Self::Output + where F: FnOnce(&T) -> R; +} + +impl InternAs<[T], R> for I + where E: InternIteratorElement, + I: Iterator { + type Output = E::Output; + fn intern_with(self, f: F) -> Self::Output + where F: FnOnce(&[T]) -> R { + E::intern_with(self, f) + } +} + +pub trait InternIteratorElement: Sized { + type Output; + fn intern_with, F: FnOnce(&[T]) -> R>(iter: I, f: F) -> Self::Output; +} + +impl InternIteratorElement for T { + type Output = R; + fn intern_with, F: FnOnce(&[T]) -> R>(iter: I, f: F) -> Self::Output { + f(&iter.collect::>()) + } +} + +impl InternIteratorElement for Result { + type Output = Result; + fn intern_with, F: FnOnce(&[T]) -> R>(iter: I, f: F) -> Self::Output { + Ok(f(&iter.collect::, _>>()?)) + } +} + diff --git a/src/librustc/ty/error.rs b/src/librustc/ty/error.rs index 001f47af68..9b345c2d02 100644 --- a/src/librustc/ty/error.rs +++ b/src/librustc/ty/error.rs @@ -33,13 +33,8 @@ pub enum TypeError<'tcx> { UnsafetyMismatch(ExpectedFound), AbiMismatch(ExpectedFound), Mutability, - BoxMutability, - PtrMutability, - RefMutability, - VecMutability, TupleSize(ExpectedFound), FixedArraySize(ExpectedFound), - TyParamSize(ExpectedFound), ArgCount, RegionsDoesNotOutlive(&'tcx Region, &'tcx Region), RegionsNotSame(&'tcx Region, &'tcx Region), @@ -47,14 +42,12 @@ pub enum TypeError<'tcx> { RegionsInsufficientlyPolymorphic(BoundRegion, &'tcx Region), RegionsOverlyPolymorphic(BoundRegion, &'tcx Region), Sorts(ExpectedFound>), - IntegerAsChar, IntMismatch(ExpectedFound), FloatMismatch(ExpectedFound), Traits(ExpectedFound), BuiltinBoundsMismatch(ExpectedFound), VariadicMismatch(ExpectedFound), CyclicTy, - ConvergenceMismatch(ExpectedFound), ProjectionNameMismatched(ExpectedFound), ProjectionBoundsLength(ExpectedFound), TyParamDefaultMismatch(ExpectedFound>) @@ -99,18 +92,6 @@ impl<'tcx> fmt::Display for TypeError<'tcx> { values.found) } Mutability => write!(f, "types differ in mutability"), - BoxMutability => { - write!(f, "boxed types differ in mutability") - } - VecMutability => write!(f, "vectors differ in mutability"), - PtrMutability => write!(f, "pointers differ in mutability"), - RefMutability => write!(f, "references differ in mutability"), - TyParamSize(values) => { - write!(f, "expected a type with {} type params, \ - found one with {} type params", - values.expected, - values.found) - } FixedArraySize(values) => { write!(f, "expected an array with a fixed size of {} elements, \ found one with {} elements", @@ -167,9 +148,6 @@ impl<'tcx> fmt::Display for TypeError<'tcx> { values.found) } } - IntegerAsChar => { - write!(f, "expected an integral type, found `char`") - } IntMismatch(ref values) => { write!(f, "expected `{:?}`, found `{:?}`", values.expected, @@ -185,11 +163,6 @@ impl<'tcx> fmt::Display for TypeError<'tcx> { if values.expected { "variadic" } else { "non-variadic" }, if values.found { "variadic" } else { "non-variadic" }) } - ConvergenceMismatch(ref values) => { - write!(f, "expected {} fn, found {} function", - if values.expected { "converging" } else { "diverging" }, - if values.found { "converging" } else { "diverging" }) - } ProjectionNameMismatched(ref values) => { write!(f, "expected {}, found {}", values.expected, diff --git a/src/librustc/ty/fast_reject.rs b/src/librustc/ty/fast_reject.rs index ee1544d2d9..befc9533c3 100644 --- a/src/librustc/ty/fast_reject.rs +++ b/src/librustc/ty/fast_reject.rs @@ -24,7 +24,7 @@ pub enum SimplifiedType { FloatSimplifiedType(ast::FloatTy), AdtSimplifiedType(DefId), StrSimplifiedType, - VecSimplifiedType, + ArraySimplifiedType, PtrSimplifiedType, NeverSimplifiedType, TupleSimplifiedType(usize), @@ -57,7 +57,7 @@ pub fn simplify_type<'a, 'gcx, 'tcx>(tcx: TyCtxt<'a, 'gcx, 'tcx>, ty::TyFloat(float_type) => Some(FloatSimplifiedType(float_type)), ty::TyAdt(def, _) => Some(AdtSimplifiedType(def.did)), ty::TyStr => Some(StrSimplifiedType), - ty::TyArray(..) | ty::TySlice(_) => Some(VecSimplifiedType), + ty::TyArray(..) | ty::TySlice(_) => Some(ArraySimplifiedType), ty::TyRawPtr(_) => Some(PtrSimplifiedType), ty::TyTrait(ref trait_info) => { Some(TraitSimplifiedType(trait_info.principal.def_id())) diff --git a/src/librustc/ty/flags.rs b/src/librustc/ty/flags.rs index 1434b0e60e..649d78f9d9 100644 --- a/src/librustc/ty/flags.rs +++ b/src/librustc/ty/flags.rs @@ -11,6 +11,7 @@ use ty::subst::Substs; use ty::{self, Ty, TypeFlags, TypeFoldable}; +#[derive(Debug)] pub struct FlagComputation { pub flags: TypeFlags, @@ -182,24 +183,9 @@ impl FlagComputation { } fn add_region(&mut self, r: &ty::Region) { - match *r { - ty::ReVar(..) => { - self.add_flags(TypeFlags::HAS_RE_INFER); - self.add_flags(TypeFlags::KEEP_IN_LOCAL_TCX); - } - ty::ReSkolemized(..) => { - self.add_flags(TypeFlags::HAS_RE_INFER); - self.add_flags(TypeFlags::HAS_RE_SKOL); - self.add_flags(TypeFlags::KEEP_IN_LOCAL_TCX); - } - ty::ReLateBound(debruijn, _) => { self.add_depth(debruijn.depth); } - ty::ReEarlyBound(..) => { self.add_flags(TypeFlags::HAS_RE_EARLY_BOUND); } - ty::ReStatic | ty::ReErased => {} - _ => { self.add_flags(TypeFlags::HAS_FREE_REGIONS); } - } - - if !r.is_global() { - self.add_flags(TypeFlags::HAS_LOCAL_NAMES); + self.add_flags(r.type_flags()); + if let ty::ReLateBound(debruijn, _) = *r { + self.add_depth(debruijn.depth); } } diff --git a/src/librustc/ty/fold.rs b/src/librustc/ty/fold.rs index 886ad8cd86..b79ebdb14f 100644 --- a/src/librustc/ty/fold.rs +++ b/src/librustc/ty/fold.rs @@ -91,6 +91,9 @@ pub trait TypeFoldable<'tcx>: fmt::Debug + Clone { fn needs_subst(&self) -> bool { self.has_type_flags(TypeFlags::NEEDS_SUBST) } + fn has_re_skol(&self) -> bool { + self.has_type_flags(TypeFlags::HAS_RE_SKOL) + } fn has_closure_types(&self) -> bool { self.has_type_flags(TypeFlags::HAS_TY_CLOSURE) } @@ -173,8 +176,8 @@ pub trait TypeFolder<'gcx: 'tcx, 'tcx> : Sized { r.super_fold_with(self) } - fn fold_autoref(&mut self, ar: &adjustment::AutoRef<'tcx>) - -> adjustment::AutoRef<'tcx> { + fn fold_autoref(&mut self, ar: &adjustment::AutoBorrow<'tcx>) + -> adjustment::AutoBorrow<'tcx> { ar.super_fold_with(self) } } @@ -632,26 +635,15 @@ struct HasTypeFlagsVisitor { impl<'tcx> TypeVisitor<'tcx> for HasTypeFlagsVisitor { fn visit_ty(&mut self, t: Ty) -> bool { - t.flags.get().intersects(self.flags) + let flags = t.flags.get(); + debug!("HasTypeFlagsVisitor: t={:?} t.flags={:?} self.flags={:?}", t, flags, self.flags); + flags.intersects(self.flags) } fn visit_region(&mut self, r: &'tcx ty::Region) -> bool { - if self.flags.intersects(ty::TypeFlags::HAS_LOCAL_NAMES) { - // does this represent a region that cannot be named - // in a global way? used in fulfillment caching. - match *r { - ty::ReStatic | ty::ReEmpty | ty::ReErased => {} - _ => return true, - } - } - if self.flags.intersects(ty::TypeFlags::HAS_RE_INFER | - ty::TypeFlags::KEEP_IN_LOCAL_TCX) { - match *r { - ty::ReVar(_) | ty::ReSkolemized(..) => { return true } - _ => {} - } - } - false + let flags = r.type_flags(); + debug!("HasTypeFlagsVisitor: r={:?} r.flags={:?} self.flags={:?}", r, flags, self.flags); + flags.intersects(self.flags) } } diff --git a/src/librustc/ty/layout.rs b/src/librustc/ty/layout.rs index ed945534e1..5ce43d905e 100644 --- a/src/librustc/ty/layout.rs +++ b/src/librustc/ty/layout.rs @@ -511,11 +511,11 @@ pub struct Struct { /// If true, the size is exact, otherwise it's only a lower bound. pub sized: bool, - /// Offsets for the first byte after each field. - /// That is, field_offset(i) = offset_after_field[i - 1] and the - /// whole structure's size is the last offset, excluding padding. - // FIXME(eddyb) use small vector optimization for the common case. - pub offset_after_field: Vec + /// Offsets for the first byte of each field. + /// FIXME(eddyb) use small vector optimization for the common case. + pub offsets: Vec, + + pub min_size: Size, } impl<'a, 'gcx, 'tcx> Struct { @@ -524,7 +524,8 @@ impl<'a, 'gcx, 'tcx> Struct { align: if packed { dl.i8_align } else { dl.aggregate_align }, packed: packed, sized: true, - offset_after_field: vec![] + offsets: vec![], + min_size: Size::from_bytes(0), } } @@ -534,12 +535,14 @@ impl<'a, 'gcx, 'tcx> Struct { scapegoat: Ty<'gcx>) -> Result<(), LayoutError<'gcx>> where I: Iterator>> { - self.offset_after_field.reserve(fields.size_hint().0); + self.offsets.reserve(fields.size_hint().0); + + let mut offset = self.min_size; for field in fields { if !self.sized { bug!("Struct::extend: field #{} of `{}` comes after unsized field", - self.offset_after_field.len(), scapegoat); + self.offsets.len(), scapegoat); } let field = field?; @@ -548,34 +551,29 @@ impl<'a, 'gcx, 'tcx> Struct { } // Invariant: offset < dl.obj_size_bound() <= 1<<61 - let mut offset = if !self.packed { + if !self.packed { let align = field.align(dl); self.align = self.align.max(align); - self.offset_after_field.last_mut().map_or(Size::from_bytes(0), |last| { - *last = last.abi_align(align); - *last - }) - } else { - self.offset_after_field.last().map_or(Size::from_bytes(0), |&last| last) - }; + offset = offset.abi_align(align); + } + + self.offsets.push(offset); + offset = offset.checked_add(field.size(dl), dl) .map_or(Err(LayoutError::SizeOverflow(scapegoat)), Ok)?; - - self.offset_after_field.push(offset); } + self.min_size = offset; + Ok(()) } /// Get the size without trailing alignment padding. - pub fn min_size(&self) -> Size { - self.offset_after_field.last().map_or(Size::from_bytes(0), |&last| last) - } /// Get the size with trailing aligment padding. pub fn stride(&self) -> Size { - self.min_size().abi_align(self.align) + self.min_size.abi_align(self.align) } /// Determine whether a structure would be zero-sized, given its fields. @@ -599,7 +597,8 @@ impl<'a, 'gcx, 'tcx> Struct { -> Result, LayoutError<'gcx>> { let tcx = infcx.tcx.global_tcx(); match (ty.layout(infcx)?, &ty.sty) { - (&Scalar { non_zero: true, .. }, _) => Ok(Some(vec![])), + (&Scalar { non_zero: true, .. }, _) | + (&CEnum { non_zero: true, .. }, _) => Ok(Some(vec![])), (&FatPointer { non_zero: true, .. }, _) => { Ok(Some(vec![FAT_PTR_ADDR as u32])) } @@ -671,15 +670,6 @@ impl<'a, 'gcx, 'tcx> Struct { } Ok(None) } - - pub fn offset_of_field(&self, index: usize) -> Size { - assert!(index < self.offset_after_field.len()); - if index == 0 { - Size::from_bytes(0) - } else { - self.offset_after_field[index-1] - } - } } /// An untagged union. @@ -780,6 +770,7 @@ pub enum Layout { CEnum { discr: Integer, signed: bool, + non_zero: bool, // Inclusive discriminant range. // If min > max, it represents min...u64::MAX followed by 0...max. // FIXME(eddyb) always use the shortest range, e.g. by finding @@ -1013,9 +1004,10 @@ impl<'a, 'gcx, 'tcx> Layout { if def.is_enum() && def.variants.iter().all(|v| v.fields.is_empty()) { // All bodies empty -> intlike - let (mut min, mut max) = (i64::MAX, i64::MIN); + let (mut min, mut max, mut non_zero) = (i64::MAX, i64::MIN, true); for v in &def.variants { let x = v.disr_val.to_u64_unchecked() as i64; + if x == 0 { non_zero = false; } if x < min { min = x; } if x > max { max = x; } } @@ -1024,6 +1016,7 @@ impl<'a, 'gcx, 'tcx> Layout { return success(CEnum { discr: discr, signed: signed, + non_zero: non_zero, min: min as u64, max: max as u64 }); @@ -1080,19 +1073,17 @@ impl<'a, 'gcx, 'tcx> Layout { // FIXME(eddyb) should take advantage of a newtype. if path == &[0] && variants[discr].len() == 1 { - match *variants[discr][0].layout(infcx)? { - Scalar { value, .. } => { - return success(RawNullablePointer { - nndiscr: discr as u64, - value: value - }); - } - _ => { - bug!("Layout::compute: `{}`'s non-zero \ - `{}` field not scalar?!", - ty, variants[discr][0]) - } - } + let value = match *variants[discr][0].layout(infcx)? { + Scalar { value, .. } => value, + CEnum { discr, .. } => Int(discr), + _ => bug!("Layout::compute: `{}`'s non-zero \ + `{}` field not scalar?!", + ty, variants[discr][0]) + }; + return success(RawNullablePointer { + nndiscr: discr as u64, + value: value, + }); } path.push(0); // For GEP through a pointer. @@ -1138,7 +1129,7 @@ impl<'a, 'gcx, 'tcx> Layout { }); let mut st = Struct::new(dl, false); st.extend(dl, discr.iter().map(Ok).chain(fields), ty)?; - size = cmp::max(size, st.min_size()); + size = cmp::max(size, st.min_size); align = align.max(st.align); Ok(st) }).collect::, _>>()?; @@ -1171,12 +1162,16 @@ impl<'a, 'gcx, 'tcx> Layout { let old_ity_size = Int(min_ity).size(dl); let new_ity_size = Int(ity).size(dl); for variant in &mut variants { - for offset in &mut variant.offset_after_field { + for offset in &mut variant.offsets[1..] { if *offset > old_ity_size { break; } *offset = new_ity_size; } + // We might be making the struct larger. + if variant.min_size <= old_ity_size { + variant.min_size = new_ity_size; + } } } diff --git a/src/librustc/ty/maps.rs b/src/librustc/ty/maps.rs index 3a552a8b43..cad87081a9 100644 --- a/src/librustc/ty/maps.rs +++ b/src/librustc/ty/maps.rs @@ -10,7 +10,10 @@ use dep_graph::{DepNode, DepTrackingMapConfig}; use hir::def_id::DefId; +use mir; use ty::{self, Ty}; + +use std::cell::RefCell; use std::marker::PhantomData; use std::rc::Rc; use syntax::{attr, ast}; @@ -43,3 +46,4 @@ dep_map_ty! { InherentImpls: InherentImpls(DefId) -> Vec } dep_map_ty! { TraitItems: TraitItems(DefId) -> Rc>> } dep_map_ty! { ReprHints: ReprHints(DefId) -> Rc> } dep_map_ty! { InlinedClosures: Hir(DefId) -> ast::NodeId } +dep_map_ty! { Mir: Mir(DefId) -> &'tcx RefCell> } diff --git a/src/librustc/ty/mod.rs b/src/librustc/ty/mod.rs index d38a30ee63..2c15f08e89 100644 --- a/src/librustc/ty/mod.rs +++ b/src/librustc/ty/mod.rs @@ -20,10 +20,11 @@ pub use self::fold::TypeFoldable; use dep_graph::{self, DepNode}; use hir::map as ast_map; use middle; -use hir::def::{Def, PathResolution, ExportMap}; +use hir::def::{Def, CtorKind, PathResolution, ExportMap}; use hir::def_id::{CrateNum, DefId, CRATE_DEF_INDEX, LOCAL_CRATE}; use middle::lang_items::{FnTraitLangItem, FnMutTraitLangItem, FnOnceTraitLangItem}; use middle::region::{CodeExtent, ROOT_CODE_EXTENT}; +use mir::Mir; use traits; use ty; use ty::subst::{Subst, Substs}; @@ -34,13 +35,14 @@ use util::nodemap::FnvHashMap; use serialize::{self, Encodable, Encoder}; use std::borrow::Cow; -use std::cell::{Cell, RefCell}; +use std::cell::{Cell, RefCell, Ref}; use std::hash::{Hash, Hasher}; use std::iter; use std::ops::Deref; use std::rc::Rc; use std::slice; use std::vec::IntoIter; +use std::mem; use syntax::ast::{self, Name, NodeId}; use syntax::attr; use syntax::parse::token::{self, InternedString}; @@ -477,6 +479,7 @@ bitflags! { TypeFlags::HAS_SELF.bits | TypeFlags::HAS_TY_INFER.bits | TypeFlags::HAS_RE_INFER.bits | + TypeFlags::HAS_RE_SKOL.bits | TypeFlags::HAS_RE_EARLY_BOUND.bits | TypeFlags::HAS_FREE_REGIONS.bits | TypeFlags::HAS_TY_ERR.bits | @@ -521,7 +524,7 @@ pub type Ty<'tcx> = &'tcx TyS<'tcx>; impl<'tcx> serialize::UseSpecializedEncodable for Ty<'tcx> {} impl<'tcx> serialize::UseSpecializedDecodable for Ty<'tcx> {} -/// A wrapper for slices with the additioanl invariant +/// A wrapper for slices with the additional invariant /// that the slice is interned and no other slice with /// the same contents can exist in the same context. /// This means we can use pointer + length for both @@ -560,6 +563,14 @@ impl<'a, T> IntoIterator for &'a Slice { impl<'tcx> serialize::UseSpecializedDecodable for &'tcx Slice> {} +impl Slice { + pub fn empty<'a>() -> &'a Slice { + unsafe { + mem::transmute(slice::from_raw_parts(0x1 as *const T, 0)) + } + } +} + /// 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. @@ -680,6 +691,11 @@ pub struct TypeParameterDef<'tcx> { pub default_def_id: DefId, // for use in error reporing about defaults pub default: Option>, pub object_lifetime_default: ObjectLifetimeDefault<'tcx>, + + /// `pure_wrt_drop`, set by the (unsafe) `#[may_dangle]` attribute + /// on generic parameter `T`, asserts data behind the parameter + /// `T` won't be accessed during the parent type's `Drop` impl. + pub pure_wrt_drop: bool, } #[derive(Clone, RustcEncodable, RustcDecodable)] @@ -688,6 +704,11 @@ pub struct RegionParameterDef<'tcx> { pub def_id: DefId, pub index: u32, pub bounds: Vec<&'tcx ty::Region>, + + /// `pure_wrt_drop`, set by the (unsafe) `#[may_dangle]` attribute + /// on generic parameter `'a`, asserts data of lifetime `'a` + /// won't be accessed during the parent type's `Drop` impl. + pub pure_wrt_drop: bool, } impl<'tcx> RegionParameterDef<'tcx> { @@ -732,6 +753,14 @@ impl<'tcx> Generics<'tcx> { pub fn count(&self) -> usize { self.parent_count() + self.own_count() } + + pub fn region_param(&self, param: &EarlyBoundRegion) -> &RegionParameterDef<'tcx> { + &self.regions[param.index as usize - self.has_self as usize] + } + + pub fn type_param(&self, param: &ParamTy) -> &TypeParameterDef<'tcx> { + &self.types[param.idx as usize - self.has_self as usize - self.regions.len()] + } } /// Bounds on generics. @@ -1428,7 +1457,7 @@ pub struct VariantDefData<'tcx, 'container: 'tcx> { pub name: Name, // struct's name if this is a struct pub disr_val: Disr, pub fields: Vec>, - pub kind: VariantKind, + pub ctor_kind: CtorKind, } pub struct FieldDefData<'tcx, 'container: 'tcx> { @@ -1493,19 +1522,6 @@ impl<'tcx> serialize::UseSpecializedDecodable for AdtDef<'tcx> {} #[derive(Copy, Clone, Debug, Eq, PartialEq)] pub enum AdtKind { Struct, Union, Enum } -#[derive(Clone, Copy, PartialEq, Eq, Hash, Debug, RustcEncodable, RustcDecodable)] -pub enum VariantKind { Struct, Tuple, Unit } - -impl VariantKind { - pub fn from_variant_data(vdata: &hir::VariantData) -> Self { - match *vdata { - hir::VariantData::Struct(..) => VariantKind::Struct, - hir::VariantData::Tuple(..) => VariantKind::Tuple, - hir::VariantData::Unit(..) => VariantKind::Unit, - } - } -} - impl<'a, 'gcx, 'tcx, 'container> AdtDefData<'gcx, 'container> { fn new(tcx: TyCtxt<'a, 'gcx, 'tcx>, did: DefId, @@ -1681,9 +1697,9 @@ impl<'a, 'gcx, 'tcx, 'container> AdtDefData<'gcx, 'container> { pub fn variant_of_def(&self, def: Def) -> &VariantDefData<'gcx, 'container> { match def { - Def::Variant(vid) => self.variant_with_id(vid), - Def::Struct(..) | Def::Union(..) | - Def::TyAlias(..) | Def::AssociatedTy(..) => self.struct_variant(), + Def::Variant(vid) | Def::VariantCtor(vid, ..) => self.variant_with_id(vid), + Def::Struct(..) | Def::StructCtor(..) | Def::Union(..) | + Def::TyAlias(..) | Def::AssociatedTy(..) | Def::SelfTy(..) => self.struct_variant(), _ => bug!("unexpected def {:?} in variant_of_def", def) } } @@ -1792,7 +1808,7 @@ impl<'a, 'tcx> AdtDefData<'tcx, 'tcx> { _ if tys.references_error() => tcx.types.err, 0 => tcx.types.bool, 1 => tys[0], - _ => tcx.mk_tup(tys) + _ => tcx.intern_tup(&tys[..]) }; match self.sized_constraint.get(dep_node()) { @@ -1868,7 +1884,7 @@ impl<'a, 'tcx> AdtDefData<'tcx, 'tcx> { }; let sized_predicate = Binder(TraitRef { def_id: sized_trait, - substs: Substs::new_trait(tcx, ty, &[]) + substs: tcx.mk_substs_trait(ty, &[]) }).to_predicate(); let predicates = tcx.lookup_predicates(self.did).predicates; if predicates.into_iter().any(|p| p == sized_predicate) { @@ -2104,80 +2120,8 @@ impl BorrowKind { } impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> { - pub fn node_id_to_type(self, id: NodeId) -> Ty<'gcx> { - match self.node_id_to_type_opt(id) { - Some(ty) => ty, - None => bug!("node_id_to_type: no type for node `{}`", - self.map.node_to_string(id)) - } - } - - pub fn node_id_to_type_opt(self, id: NodeId) -> Option> { - self.tables.borrow().node_types.get(&id).cloned() - } - - pub fn node_id_item_substs(self, id: NodeId) -> ItemSubsts<'gcx> { - match self.tables.borrow().item_substs.get(&id) { - None => ItemSubsts { - substs: Substs::empty(self.global_tcx()) - }, - Some(ts) => ts.clone(), - } - } - - // Returns the type of a pattern as a monotype. Like @expr_ty, this function - // doesn't provide type parameter substitutions. - pub fn pat_ty(self, pat: &hir::Pat) -> Ty<'gcx> { - self.node_id_to_type(pat.id) - } - pub fn pat_ty_opt(self, pat: &hir::Pat) -> Option> { - self.node_id_to_type_opt(pat.id) - } - - // Returns the type of an expression as a monotype. - // - // NB (1): This is the PRE-ADJUSTMENT TYPE for the expression. That is, in - // some cases, we insert `AutoAdjustment` annotations such as auto-deref or - // auto-ref. The type returned by this function does not consider such - // adjustments. See `expr_ty_adjusted()` instead. - // - // NB (2): This type doesn't provide type parameter substitutions; e.g. if you - // ask for the type of "id" in "id(3)", it will return "fn(&isize) -> isize" - // instead of "fn(ty) -> T with T = isize". - pub fn expr_ty(self, expr: &hir::Expr) -> Ty<'gcx> { - self.node_id_to_type(expr.id) - } - - pub fn expr_ty_opt(self, expr: &hir::Expr) -> Option> { - self.node_id_to_type_opt(expr.id) - } - - /// Returns the type of `expr`, considering any `AutoAdjustment` - /// entry recorded for that expression. - /// - /// It would almost certainly be better to store the adjusted ty in with - /// the `AutoAdjustment`, but I opted not to do this because it would - /// require serializing and deserializing the type and, although that's not - /// hard to do, I just hate that code so much I didn't want to touch it - /// unless it was to fix it properly, which seemed a distraction from the - /// thread at hand! -nmatsakis - pub fn expr_ty_adjusted(self, expr: &hir::Expr) -> Ty<'gcx> { - self.expr_ty(expr) - .adjust(self.global_tcx(), expr.span, expr.id, - self.tables.borrow().adjustments.get(&expr.id), - |method_call| { - self.tables.borrow().method_map.get(&method_call).map(|method| method.ty) - }) - } - - pub fn expr_ty_adjusted_opt(self, expr: &hir::Expr) -> Option> { - self.expr_ty_opt(expr).map(|t| t.adjust(self.global_tcx(), - expr.span, - expr.id, - self.tables.borrow().adjustments.get(&expr.id), - |method_call| { - self.tables.borrow().method_map.get(&method_call).map(|method| method.ty) - })) + pub fn tables(self) -> Ref<'a, Tables<'gcx>> { + self.tables.borrow() } pub fn expr_span(self, id: NodeId) -> Span { @@ -2240,7 +2184,7 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> { hir::ExprClosure(..) | hir::ExprBlock(..) | hir::ExprRepeat(..) | - hir::ExprVec(..) | + hir::ExprArray(..) | hir::ExprBreak(..) | hir::ExprAgain(..) | hir::ExprRet(..) | @@ -2340,13 +2284,17 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> { // or variant or their constructors, panics otherwise. pub fn expect_variant_def(self, def: Def) -> VariantDef<'tcx> { match def { - Def::Variant(did) => { + Def::Variant(did) | Def::VariantCtor(did, ..) => { let enum_did = self.parent_def_id(did).unwrap(); self.lookup_adt_def(enum_did).variant_with_id(did) } Def::Struct(did) | Def::Union(did) => { self.lookup_adt_def(did).struct_variant() } + Def::StructCtor(ctor_did, ..) => { + let did = self.parent_def_id(ctor_did).expect("struct ctor has no parent"); + self.lookup_adt_def(did).struct_variant() + } _ => bug!("expect_variant_def used with unexpected def {:?}", def) } } @@ -2500,6 +2448,19 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> { || self.sess.cstore.item_super_predicates(self.global_tcx(), did)) } + /// Given the did of an item, returns its MIR, borrowed immutably. + pub fn item_mir(self, did: DefId) -> Ref<'gcx, Mir<'gcx>> { + lookup_locally_or_in_crate_store("mir_map", did, &self.mir_map, || { + let mir = self.sess.cstore.get_item_mir(self.global_tcx(), did); + let mir = self.alloc_mir(mir); + + // Perma-borrow MIR from extern crates to prevent mutation. + mem::forget(mir.borrow()); + + mir + }).borrow() + } + /// If `type_needs_drop` returns true, then `ty` is definitely /// non-copy and *might* have a destructor attached; if it returns /// false, then `ty` definitely has no destructor (i.e. no drop glue). @@ -2787,7 +2748,7 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> { // regions, so it shouldn't matter what we use for the free id let free_id_outlive = self.region_maps.node_extent(ast::DUMMY_NODE_ID); ty::ParameterEnvironment { - free_substs: Substs::empty(self), + free_substs: self.intern_substs(&[]), caller_bounds: Vec::new(), implicit_region_bound: self.mk_region(ty::ReEmpty), free_id_outlive: free_id_outlive, @@ -2875,19 +2836,6 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> { self.mk_region(ty::ReScope(self.region_maps.node_extent(id))) } - pub fn is_method_call(self, expr_id: NodeId) -> bool { - self.tables.borrow().method_map.contains_key(&MethodCall::expr(expr_id)) - } - - pub fn is_overloaded_autoderef(self, expr_id: NodeId, autoderefs: u32) -> bool { - self.tables.borrow().method_map.contains_key(&MethodCall::autoderef(expr_id, - autoderefs)) - } - - pub fn upvar_capture(self, upvar_id: ty::UpvarId) -> Option> { - Some(self.tables.borrow().upvar_capture_map.get(&upvar_id).unwrap().clone()) - } - pub fn visit_all_items_in_krate(self, dep_node_fn: F, visitor: &mut V) diff --git a/src/librustc/ty/outlives.rs b/src/librustc/ty/outlives.rs index a4edd3b93c..51feab9d40 100644 --- a/src/librustc/ty/outlives.rs +++ b/src/librustc/ty/outlives.rs @@ -12,8 +12,7 @@ // refers to rules defined in RFC 1214 (`OutlivesFooBar`), so see that // RFC for reference. -use infer::InferCtxt; -use ty::{self, Ty, TypeFoldable}; +use ty::{self, Ty, TyCtxt, TypeFoldable}; #[derive(Debug)] pub enum Component<'tcx> { @@ -55,9 +54,9 @@ pub enum Component<'tcx> { EscapingProjection(Vec>), } -impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> { +impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> { /// Returns all the things that must outlive `'a` for the condition - /// `ty0: 'a` to hold. + /// `ty0: 'a` to hold. Note that `ty0` must be a **fully resolved type**. pub fn outlives_components(&self, ty0: Ty<'tcx>) -> Vec> { let mut components = vec![]; @@ -148,16 +147,11 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> { } } - // If we encounter an inference variable, try to resolve it - // and proceed with resolved version. If we cannot resolve it, - // then record the unresolved variable as a component. - ty::TyInfer(_) => { - let ty = self.resolve_type_vars_if_possible(&ty); - if let ty::TyInfer(infer_ty) = ty.sty { - out.push(Component::UnresolvedInferenceVariable(infer_ty)); - } else { - self.compute_components(ty, out); - } + // We assume that inference variables are fully resolved. + // So, if we encounter an inference variable, just record + // the unresolved variable as a component. + ty::TyInfer(infer_ty) => { + out.push(Component::UnresolvedInferenceVariable(infer_ty)); } // Most types do not introduce any region binders, nor diff --git a/src/librustc/ty/relate.rs b/src/librustc/ty/relate.rs index b10c731fe2..cb90e6392c 100644 --- a/src/librustc/ty/relate.rs +++ b/src/librustc/ty/relate.rs @@ -49,12 +49,6 @@ pub trait TypeRelation<'a, 'gcx: 'a+'tcx, 'tcx: 'a> : Sized { Relate::relate(self, a, b) } - /// Relete elements of two slices pairwise. - fn relate_zip>(&mut self, a: &[T], b: &[T]) -> RelateResult<'tcx, Vec> { - assert_eq!(a.len(), b.len()); - a.iter().zip(b).map(|(a, b)| self.relate(a, b)).collect() - } - /// Switch variance for the purpose of relating `a` and `b`. fn relate_with_variance>(&mut self, variance: ty::Variance, @@ -158,7 +152,7 @@ pub fn relate_substs<'a, 'gcx, 'tcx, R>(relation: &mut R, } }); - Substs::maybe_new(tcx, params) + Ok(tcx.mk_substs(params)?) } impl<'tcx> Relate<'tcx> for &'tcx ty::BareFnTy<'tcx> { @@ -489,10 +483,7 @@ pub fn super_relate_tys<'a, 'gcx, 'tcx, R>(relation: &mut R, (&ty::TyTuple(as_), &ty::TyTuple(bs)) => { if as_.len() == bs.len() { - let ts = as_.iter().zip(bs) - .map(|(a, b)| relation.relate(a, b)) - .collect::>()?; - Ok(tcx.mk_tup(ts)) + Ok(tcx.mk_tup(as_.iter().zip(bs).map(|(a, b)| relation.relate(a, b)))?) } else if !(as_.is_empty() || bs.is_empty()) { Err(TypeError::TupleSize( expected_found(relation, &as_.len(), &bs.len()))) @@ -544,10 +535,11 @@ impl<'tcx> Relate<'tcx> for ty::ClosureSubsts<'tcx> { where R: TypeRelation<'a, 'gcx, 'tcx>, 'gcx: 'a+'tcx, 'tcx: 'a { let substs = relate_substs(relation, None, a.func_substs, b.func_substs)?; - let upvar_tys = relation.relate_zip(&a.upvar_tys, &b.upvar_tys)?; + assert_eq!(a.upvar_tys.len(), b.upvar_tys.len()); Ok(ty::ClosureSubsts { func_substs: substs, - upvar_tys: relation.tcx().mk_type_list(upvar_tys) + upvar_tys: relation.tcx().mk_type_list( + a.upvar_tys.iter().zip(b.upvar_tys).map(|(a, b)| relation.relate(a, b)))? }) } } diff --git a/src/librustc/ty/structural_impls.rs b/src/librustc/ty/structural_impls.rs index 1715185373..9ca911837b 100644 --- a/src/librustc/ty/structural_impls.rs +++ b/src/librustc/ty/structural_impls.rs @@ -11,6 +11,7 @@ use infer::type_variable; use ty::{self, Lift, Ty, TyCtxt}; use ty::fold::{TypeFoldable, TypeFolder, TypeVisitor}; +use rustc_data_structures::accumulate_vec::AccumulateVec; use std::rc::Rc; use syntax::abi; @@ -217,15 +218,15 @@ impl<'a, 'tcx> Lift<'tcx> for ty::ItemSubsts<'a> { } } -impl<'a, 'tcx> Lift<'tcx> for ty::adjustment::AutoRef<'a> { - type Lifted = ty::adjustment::AutoRef<'tcx>; +impl<'a, 'tcx> Lift<'tcx> for ty::adjustment::AutoBorrow<'a> { + type Lifted = ty::adjustment::AutoBorrow<'tcx>; fn lift_to_tcx<'b, 'gcx>(&self, tcx: TyCtxt<'b, 'gcx, 'tcx>) -> Option { match *self { - ty::adjustment::AutoPtr(r, m) => { - tcx.lift(&r).map(|r| ty::adjustment::AutoPtr(r, m)) + ty::adjustment::AutoBorrow::Ref(r, m) => { + tcx.lift(&r).map(|r| ty::adjustment::AutoBorrow::Ref(r, m)) } - ty::adjustment::AutoUnsafe(m) => { - Some(ty::adjustment::AutoUnsafe(m)) + ty::adjustment::AutoBorrow::RawPtr(m) => { + Some(ty::adjustment::AutoBorrow::RawPtr(m)) } } } @@ -296,13 +297,8 @@ impl<'a, 'tcx> Lift<'tcx> for ty::error::TypeError<'a> { UnsafetyMismatch(x) => UnsafetyMismatch(x), AbiMismatch(x) => AbiMismatch(x), Mutability => Mutability, - BoxMutability => BoxMutability, - PtrMutability => PtrMutability, - RefMutability => RefMutability, - VecMutability => VecMutability, TupleSize(x) => TupleSize(x), FixedArraySize(x) => FixedArraySize(x), - TyParamSize(x) => TyParamSize(x), ArgCount => ArgCount, RegionsDoesNotOutlive(a, b) => { return tcx.lift(&(a, b)).map(|(a, b)| RegionsDoesNotOutlive(a, b)) @@ -319,14 +315,12 @@ impl<'a, 'tcx> Lift<'tcx> for ty::error::TypeError<'a> { RegionsOverlyPolymorphic(a, b) => { return tcx.lift(&b).map(|b| RegionsOverlyPolymorphic(a, b)) } - IntegerAsChar => IntegerAsChar, IntMismatch(x) => IntMismatch(x), FloatMismatch(x) => FloatMismatch(x), Traits(x) => Traits(x), BuiltinBoundsMismatch(x) => BuiltinBoundsMismatch(x), VariadicMismatch(x) => VariadicMismatch(x), CyclicTy => CyclicTy, - ConvergenceMismatch(x) => ConvergenceMismatch(x), ProjectionNameMismatched(x) => ProjectionNameMismatched(x), ProjectionBoundsLength(x) => ProjectionBoundsLength(x), @@ -455,8 +449,8 @@ impl<'tcx> TypeFoldable<'tcx> for ty::TraitObject<'tcx> { impl<'tcx> TypeFoldable<'tcx> for &'tcx ty::Slice> { fn super_fold_with<'gcx: 'tcx, F: TypeFolder<'gcx, 'tcx>>(&self, folder: &mut F) -> Self { - let tys = self.iter().map(|t| t.fold_with(folder)).collect(); - folder.tcx().mk_type_list(tys) + let v = self.iter().map(|t| t.fold_with(folder)).collect::>(); + folder.tcx().intern_type_list(&v) } fn super_visit_with>(&self, visitor: &mut V) -> bool { @@ -682,13 +676,13 @@ impl<'tcx> TypeFoldable<'tcx> for ty::ItemSubsts<'tcx> { } } -impl<'tcx> TypeFoldable<'tcx> for ty::adjustment::AutoRef<'tcx> { +impl<'tcx> TypeFoldable<'tcx> for ty::adjustment::AutoBorrow<'tcx> { fn super_fold_with<'gcx: 'tcx, F: TypeFolder<'gcx, 'tcx>>(&self, folder: &mut F) -> Self { match *self { - ty::adjustment::AutoPtr(ref r, m) => { - ty::adjustment::AutoPtr(r.fold_with(folder), m) + ty::adjustment::AutoBorrow::Ref(ref r, m) => { + ty::adjustment::AutoBorrow::Ref(r.fold_with(folder), m) } - ty::adjustment::AutoUnsafe(m) => ty::adjustment::AutoUnsafe(m) + ty::adjustment::AutoBorrow::RawPtr(m) => ty::adjustment::AutoBorrow::RawPtr(m) } } @@ -698,8 +692,8 @@ impl<'tcx> TypeFoldable<'tcx> for ty::adjustment::AutoRef<'tcx> { fn super_visit_with>(&self, visitor: &mut V) -> bool { match *self { - ty::adjustment::AutoPtr(r, _m) => r.visit_with(visitor), - ty::adjustment::AutoUnsafe(_m) => false, + ty::adjustment::AutoBorrow::Ref(r, _m) => r.visit_with(visitor), + ty::adjustment::AutoBorrow::RawPtr(_m) => false, } } } @@ -723,6 +717,7 @@ impl<'tcx> TypeFoldable<'tcx> for ty::TypeParameterDef<'tcx> { default: self.default.fold_with(folder), default_def_id: self.default_def_id, object_lifetime_default: self.object_lifetime_default.fold_with(folder), + pure_wrt_drop: self.pure_wrt_drop, } } @@ -761,6 +756,7 @@ impl<'tcx> TypeFoldable<'tcx> for ty::RegionParameterDef<'tcx> { def_id: self.def_id, index: self.index, bounds: self.bounds.fold_with(folder), + pure_wrt_drop: self.pure_wrt_drop, } } diff --git a/src/librustc/ty/sty.rs b/src/librustc/ty/sty.rs index 302cab0446..92dfb883ef 100644 --- a/src/librustc/ty/sty.rs +++ b/src/librustc/ty/sty.rs @@ -406,7 +406,7 @@ impl Binder { impl fmt::Debug for TypeFlags { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - write!(f, "{}", self.bits) + write!(f, "{:x}", self.bits) } } @@ -866,6 +866,35 @@ impl Region { r => r } } + + pub fn type_flags(&self) -> TypeFlags { + let mut flags = TypeFlags::empty(); + + match *self { + ty::ReVar(..) => { + flags = flags | TypeFlags::HAS_RE_INFER; + flags = flags | TypeFlags::KEEP_IN_LOCAL_TCX; + } + ty::ReSkolemized(..) => { + flags = flags | TypeFlags::HAS_RE_INFER; + flags = flags | TypeFlags::HAS_RE_SKOL; + flags = flags | TypeFlags::KEEP_IN_LOCAL_TCX; + } + ty::ReLateBound(..) => { } + ty::ReEarlyBound(..) => { flags = flags | TypeFlags::HAS_RE_EARLY_BOUND; } + ty::ReStatic | ty::ReErased => { } + _ => { flags = flags | TypeFlags::HAS_FREE_REGIONS; } + } + + match *self { + ty::ReStatic | ty::ReEmpty | ty::ReErased => (), + _ => flags = flags | TypeFlags::HAS_LOCAL_NAMES, + } + + debug!("type_flags({:?}) = {:?}", self, flags); + + flags + } } // Type utilities diff --git a/src/librustc/ty/subst.rs b/src/librustc/ty/subst.rs index 6911d21742..a4ceecd8c9 100644 --- a/src/librustc/ty/subst.rs +++ b/src/librustc/ty/subst.rs @@ -11,11 +11,12 @@ // Type substitutions. use hir::def_id::DefId; -use ty::{self, Ty, TyCtxt}; +use ty::{self, Slice, Ty, TyCtxt}; use ty::fold::{TypeFoldable, TypeFolder, TypeVisitor}; use serialize::{self, Encodable, Encoder, Decodable, Decoder}; use syntax_pos::{Span, DUMMY_SP}; +use rustc_data_structures::accumulate_vec::AccumulateVec; use core::nonzero::NonZero; use std::fmt; @@ -161,41 +162,9 @@ impl<'tcx> Decodable for Kind<'tcx> { } /// A substitution mapping type/region parameters to new values. -#[derive(Clone, PartialEq, Eq, Debug, Hash, RustcEncodable, RustcDecodable)] -pub struct Substs<'tcx> { - params: Vec> -} +pub type Substs<'tcx> = Slice>; impl<'a, 'gcx, 'tcx> Substs<'tcx> { - pub fn new(tcx: TyCtxt<'a, 'gcx, 'tcx>, params: I) - -> &'tcx Substs<'tcx> - where I: IntoIterator> { - tcx.mk_substs(Substs { - params: params.into_iter().collect() - }) - } - - pub fn maybe_new(tcx: TyCtxt<'a, 'gcx, 'tcx>, params: I) - -> Result<&'tcx Substs<'tcx>, E> - where I: IntoIterator, E>> { - Ok(tcx.mk_substs(Substs { - params: params.into_iter().collect::>()? - })) - } - - pub fn new_trait(tcx: TyCtxt<'a, 'gcx, 'tcx>, - s: Ty<'tcx>, - t: &[Ty<'tcx>]) - -> &'tcx Substs<'tcx> - { - let t = iter::once(s).chain(t.iter().cloned()); - Substs::new(tcx, t.map(Kind::from)) - } - - pub fn empty(tcx: TyCtxt<'a, 'gcx, 'tcx>) -> &'tcx Substs<'tcx> { - Substs::new(tcx, vec![]) - } - /// Creates a Substs for generic parameter definitions, /// by calling closures to obtain each region and type. /// The closures get to observe the Substs as they're @@ -206,82 +175,80 @@ impl<'a, 'gcx, 'tcx> Substs<'tcx> { mut mk_region: FR, mut mk_type: FT) -> &'tcx Substs<'tcx> - where FR: FnMut(&ty::RegionParameterDef, &Substs<'tcx>) -> &'tcx ty::Region, - FT: FnMut(&ty::TypeParameterDef<'tcx>, &Substs<'tcx>) -> Ty<'tcx> { + where FR: FnMut(&ty::RegionParameterDef, &[Kind<'tcx>]) -> &'tcx ty::Region, + FT: FnMut(&ty::TypeParameterDef<'tcx>, &[Kind<'tcx>]) -> Ty<'tcx> { let defs = tcx.lookup_generics(def_id); - let mut substs = Substs { - params: Vec::with_capacity(defs.count()) - }; - - substs.fill_item(tcx, defs, &mut mk_region, &mut mk_type); - - tcx.mk_substs(substs) + let mut substs = Vec::with_capacity(defs.count()); + Substs::fill_item(&mut substs, tcx, defs, &mut mk_region, &mut mk_type); + tcx.intern_substs(&substs) } - fn fill_item(&mut self, + fn fill_item(substs: &mut Vec>, tcx: TyCtxt<'a, 'gcx, 'tcx>, defs: &ty::Generics<'tcx>, mk_region: &mut FR, mk_type: &mut FT) - where FR: FnMut(&ty::RegionParameterDef, &Substs<'tcx>) -> &'tcx ty::Region, - FT: FnMut(&ty::TypeParameterDef<'tcx>, &Substs<'tcx>) -> Ty<'tcx> { + where FR: FnMut(&ty::RegionParameterDef, &[Kind<'tcx>]) -> &'tcx ty::Region, + FT: FnMut(&ty::TypeParameterDef<'tcx>, &[Kind<'tcx>]) -> Ty<'tcx> { + if let Some(def_id) = defs.parent { let parent_defs = tcx.lookup_generics(def_id); - self.fill_item(tcx, parent_defs, mk_region, mk_type); + Substs::fill_item(substs, tcx, parent_defs, mk_region, mk_type); } // Handle Self first, before all regions. let mut types = defs.types.iter(); if defs.parent.is_none() && defs.has_self { let def = types.next().unwrap(); - let ty = mk_type(def, self); - assert_eq!(def.index as usize, self.params.len()); - self.params.push(Kind::from(ty)); + let ty = mk_type(def, substs); + assert_eq!(def.index as usize, substs.len()); + substs.push(Kind::from(ty)); } for def in &defs.regions { - let region = mk_region(def, self); - assert_eq!(def.index as usize, self.params.len()); - self.params.push(Kind::from(region)); + let region = mk_region(def, substs); + assert_eq!(def.index as usize, substs.len()); + substs.push(Kind::from(region)); } for def in types { - let ty = mk_type(def, self); - assert_eq!(def.index as usize, self.params.len()); - self.params.push(Kind::from(ty)); + let ty = mk_type(def, substs); + assert_eq!(def.index as usize, substs.len()); + substs.push(Kind::from(ty)); } } pub fn is_noop(&self) -> bool { - self.params.is_empty() + self.is_empty() } #[inline] pub fn params(&self) -> &[Kind<'tcx>] { - &self.params + // FIXME (dikaiosune) this should be removed, and corresponding compilation errors fixed + self } #[inline] pub fn types(&'a self) -> impl DoubleEndedIterator> + 'a { - self.params.iter().filter_map(|k| k.as_type()) + self.iter().filter_map(|k| k.as_type()) } #[inline] pub fn regions(&'a self) -> impl DoubleEndedIterator + 'a { - self.params.iter().filter_map(|k| k.as_region()) + self.iter().filter_map(|k| k.as_region()) } #[inline] pub fn type_at(&self, i: usize) -> Ty<'tcx> { - self.params[i].as_type().unwrap_or_else(|| { - bug!("expected type for param #{} in {:?}", i, self.params); + self[i].as_type().unwrap_or_else(|| { + bug!("expected type for param #{} in {:?}", i, self); }) } #[inline] pub fn region_at(&self, i: usize) -> &'tcx ty::Region { - self.params[i].as_region().unwrap_or_else(|| { - bug!("expected region for param #{} in {:?}", i, self.params); + self[i].as_region().unwrap_or_else(|| { + bug!("expected region for param #{} in {:?}", i, self); }) } @@ -305,19 +272,21 @@ impl<'a, 'gcx, 'tcx> Substs<'tcx> { target_substs: &Substs<'tcx>) -> &'tcx Substs<'tcx> { let defs = tcx.lookup_generics(source_ancestor); - tcx.mk_substs(Substs { - params: target_substs.params.iter() - .chain(&self.params[defs.own_count()..]).cloned().collect() - }) + tcx.mk_substs(target_substs.iter().chain(&self[defs.own_count()..]).cloned()) } } impl<'tcx> TypeFoldable<'tcx> for &'tcx Substs<'tcx> { fn super_fold_with<'gcx: 'tcx, F: TypeFolder<'gcx, 'tcx>>(&self, folder: &mut F) -> Self { - let params = self.params.iter().map(|k| k.fold_with(folder)).collect(); - folder.tcx().mk_substs(Substs { - params: params - }) + let params: AccumulateVec<[_; 8]> = self.iter().map(|k| k.fold_with(folder)).collect(); + + // If folding doesn't change the substs, it's faster to avoid + // calling `mk_substs` and instead reuse the existing substs. + if params[..] == self[..] { + self + } else { + folder.tcx().intern_substs(¶ms) + } } fn fold_with<'gcx: 'tcx, F: TypeFolder<'gcx, 'tcx>>(&self, folder: &mut F) -> Self { @@ -325,7 +294,7 @@ impl<'tcx> TypeFoldable<'tcx> for &'tcx Substs<'tcx> { } fn super_visit_with>(&self, visitor: &mut V) -> bool { - self.params.visit_with(visitor) + self.iter().any(|t| t.visit_with(visitor)) } } @@ -340,19 +309,19 @@ impl<'tcx> serialize::UseSpecializedDecodable for &'tcx Substs<'tcx> {} pub trait Subst<'tcx> : Sized { fn subst<'a, 'gcx>(&self, tcx: TyCtxt<'a, 'gcx, 'tcx>, - substs: &Substs<'tcx>) -> Self { + substs: &[Kind<'tcx>]) -> Self { self.subst_spanned(tcx, substs, None) } fn subst_spanned<'a, 'gcx>(&self, tcx: TyCtxt<'a, 'gcx, 'tcx>, - substs: &Substs<'tcx>, + substs: &[Kind<'tcx>], span: Option) -> Self; } impl<'tcx, T:TypeFoldable<'tcx>> Subst<'tcx> for T { fn subst_spanned<'a, 'gcx>(&self, tcx: TyCtxt<'a, 'gcx, 'tcx>, - substs: &Substs<'tcx>, + substs: &[Kind<'tcx>], span: Option) -> T { @@ -371,7 +340,7 @@ impl<'tcx, T:TypeFoldable<'tcx>> Subst<'tcx> for T { struct SubstFolder<'a, 'gcx: 'a+'tcx, 'tcx: 'a> { tcx: TyCtxt<'a, 'gcx, 'tcx>, - substs: &'a Substs<'tcx>, + substs: &'a [Kind<'tcx>], // The location for which the substitution is performed, if available. span: Option, @@ -404,7 +373,7 @@ impl<'a, 'gcx, 'tcx> TypeFolder<'gcx, 'tcx> for SubstFolder<'a, 'gcx, 'tcx> { // the specialized routine `ty::replace_late_regions()`. match *r { ty::ReEarlyBound(data) => { - let r = self.substs.params.get(data.index as usize) + let r = self.substs.get(data.index as usize) .and_then(|k| k.as_region()); match r { Some(r) => { @@ -461,7 +430,7 @@ impl<'a, 'gcx, 'tcx> TypeFolder<'gcx, 'tcx> for SubstFolder<'a, 'gcx, 'tcx> { impl<'a, 'gcx, 'tcx> SubstFolder<'a, 'gcx, 'tcx> { fn ty_for_param(&self, p: ty::ParamTy, source_ty: Ty<'tcx>) -> Ty<'tcx> { // Look up the type in the substitutions. It really should be in there. - let opt_ty = self.substs.params.get(p.idx as usize) + let opt_ty = self.substs.get(p.idx as usize) .and_then(|k| k.as_type()); let ty = match opt_ty { Some(t) => t, @@ -475,7 +444,7 @@ impl<'a, 'gcx, 'tcx> SubstFolder<'a, 'gcx, 'tcx> { source_ty, p.idx, self.root_ty, - self.substs.params); + self.substs); } }; @@ -552,10 +521,9 @@ impl<'a, 'gcx, 'tcx> ty::TraitRef<'tcx> { -> ty::TraitRef<'tcx> { let defs = tcx.lookup_generics(trait_id); - let params = substs.params[..defs.own_count()].iter().cloned(); ty::TraitRef { def_id: trait_id, - substs: Substs::new(tcx, params) + substs: tcx.intern_substs(&substs[..defs.own_count()]) } } } @@ -567,10 +535,9 @@ impl<'a, 'gcx, 'tcx> ty::ExistentialTraitRef<'tcx> { // Assert there is a Self. trait_ref.substs.type_at(0); - let params = trait_ref.substs.params[1..].iter().cloned(); ty::ExistentialTraitRef { def_id: trait_ref.def_id, - substs: Substs::new(tcx, params) + substs: tcx.intern_substs(&trait_ref.substs[1..]) } } } @@ -587,11 +554,10 @@ impl<'a, 'gcx, 'tcx> ty::PolyExistentialTraitRef<'tcx> { assert!(!self_ty.has_escaping_regions()); self.map_bound(|trait_ref| { - let params = trait_ref.substs.params.iter().cloned(); - let params = iter::once(Kind::from(self_ty)).chain(params); ty::TraitRef { def_id: trait_ref.def_id, - substs: Substs::new(tcx, params) + substs: tcx.mk_substs( + iter::once(Kind::from(self_ty)).chain(trait_ref.substs.iter().cloned())) } }) } diff --git a/src/librustc/ty/util.rs b/src/librustc/ty/util.rs index 5b0f43e3cf..cca4069ba5 100644 --- a/src/librustc/ty/util.rs +++ b/src/librustc/ty/util.rs @@ -392,27 +392,35 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> { } } -// When hashing a type this ends up affecting properties like symbol names. We -// want these symbol names to be calculated independent of other factors like -// what architecture you're compiling *from*. -// -// The hashing just uses the standard `Hash` trait, but the implementations of -// `Hash` for the `usize` and `isize` types are *not* architecture independent -// (e.g. they has 4 or 8 bytes). As a result we want to avoid `usize` and -// `isize` completely when hashing. To ensure that these don't leak in we use a -// custom hasher implementation here which inflates the size of these to a `u64` -// and `i64`. -struct WidenUsizeHasher { +/// When hashing a type this ends up affecting properties like symbol names. We +/// want these symbol names to be calculated independent of other factors like +/// what architecture you're compiling *from*. +/// +/// The hashing just uses the standard `Hash` trait, but the implementations of +/// `Hash` for the `usize` and `isize` types are *not* architecture independent +/// (e.g. they has 4 or 8 bytes). As a result we want to avoid `usize` and +/// `isize` completely when hashing. To ensure that these don't leak in we use a +/// custom hasher implementation here which inflates the size of these to a `u64` +/// and `i64`. +/// +/// The same goes for endianess: We always convert multi-byte integers to little +/// endian before hashing. +#[derive(Debug)] +pub struct ArchIndependentHasher { inner: H, } -impl WidenUsizeHasher { - fn new(inner: H) -> WidenUsizeHasher { - WidenUsizeHasher { inner: inner } +impl ArchIndependentHasher { + pub fn new(inner: H) -> ArchIndependentHasher { + ArchIndependentHasher { inner: inner } + } + + pub fn into_inner(self) -> H { + self.inner } } -impl Hasher for WidenUsizeHasher { +impl Hasher for ArchIndependentHasher { fn write(&mut self, bytes: &[u8]) { self.inner.write(bytes) } @@ -425,44 +433,44 @@ impl Hasher for WidenUsizeHasher { self.inner.write_u8(i) } fn write_u16(&mut self, i: u16) { - self.inner.write_u16(i) + self.inner.write_u16(i.to_le()) } fn write_u32(&mut self, i: u32) { - self.inner.write_u32(i) + self.inner.write_u32(i.to_le()) } fn write_u64(&mut self, i: u64) { - self.inner.write_u64(i) + self.inner.write_u64(i.to_le()) } fn write_usize(&mut self, i: usize) { - self.inner.write_u64(i as u64) + self.inner.write_u64((i as u64).to_le()) } fn write_i8(&mut self, i: i8) { self.inner.write_i8(i) } fn write_i16(&mut self, i: i16) { - self.inner.write_i16(i) + self.inner.write_i16(i.to_le()) } fn write_i32(&mut self, i: i32) { - self.inner.write_i32(i) + self.inner.write_i32(i.to_le()) } fn write_i64(&mut self, i: i64) { - self.inner.write_i64(i) + self.inner.write_i64(i.to_le()) } fn write_isize(&mut self, i: isize) { - self.inner.write_i64(i as i64) + self.inner.write_i64((i as i64).to_le()) } } pub struct TypeIdHasher<'a, 'gcx: 'a+'tcx, 'tcx: 'a, H> { tcx: TyCtxt<'a, 'gcx, 'tcx>, - state: WidenUsizeHasher, + state: ArchIndependentHasher, } impl<'a, 'gcx, 'tcx, H: Hasher> TypeIdHasher<'a, 'gcx, 'tcx, H> { pub fn new(tcx: TyCtxt<'a, 'gcx, 'tcx>, state: H) -> Self { TypeIdHasher { tcx: tcx, - state: WidenUsizeHasher::new(state), + state: ArchIndependentHasher::new(state), } } @@ -493,6 +501,10 @@ impl<'a, 'gcx, 'tcx, H: Hasher> TypeIdHasher<'a, 'gcx, 'tcx, H> { pub fn def_path(&mut self, def_path: &ast_map::DefPath) { def_path.deterministic_hash_to(self.tcx, &mut self.state); } + + pub fn into_inner(self) -> H { + self.state.inner + } } impl<'a, 'gcx, 'tcx, H: Hasher> TypeVisitor<'tcx> for TypeIdHasher<'a, 'gcx, 'tcx, H> { diff --git a/src/librustc/ty/walk.rs b/src/librustc/ty/walk.rs index dd3a62f7cd..bebdebf127 100644 --- a/src/librustc/ty/walk.rs +++ b/src/librustc/ty/walk.rs @@ -22,7 +22,7 @@ pub struct TypeWalker<'tcx> { impl<'tcx> TypeWalker<'tcx> { pub fn new(ty: Ty<'tcx>) -> TypeWalker<'tcx> { - TypeWalker { stack: vec!(ty), last_subtree: 1, } + TypeWalker { stack: vec![ty], last_subtree: 1, } } /// Skips the subtree of types corresponding to the last type diff --git a/src/librustc/ty/wf.rs b/src/librustc/ty/wf.rs index 0557660e98..155fa4989e 100644 --- a/src/librustc/ty/wf.rs +++ b/src/librustc/ty/wf.rs @@ -178,7 +178,8 @@ pub fn implied_bounds<'a, 'gcx, 'tcx>( match infcx.tcx.no_late_bound_regions(data) { None => vec![], Some(ty::OutlivesPredicate(ty_a, r_b)) => { - let components = infcx.outlives_components(ty_a); + let ty_a = infcx.resolve_type_vars_if_possible(&ty_a); + let components = infcx.tcx.outlives_components(ty_a); implied_bounds_from_components(r_b, components) } }, @@ -201,11 +202,11 @@ fn implied_bounds_from_components<'tcx>(sub_region: &'tcx ty::Region, .flat_map(|component| { match component { Component::Region(r) => - vec!(ImpliedBound::RegionSubRegion(sub_region, r)), + vec![ImpliedBound::RegionSubRegion(sub_region, r)], Component::Param(p) => - vec!(ImpliedBound::RegionSubParam(sub_region, p)), + vec![ImpliedBound::RegionSubParam(sub_region, p)], Component::Projection(p) => - vec!(ImpliedBound::RegionSubProjection(sub_region, p)), + vec![ImpliedBound::RegionSubProjection(sub_region, p)], Component::EscapingProjection(_) => // If the projection has escaping regions, don't // try to infer any implied bounds even for its @@ -215,9 +216,9 @@ fn implied_bounds_from_components<'tcx>(sub_region: &'tcx ty::Region, // idea is that the WAY that the caller proves // that may change in the future and we want to // give ourselves room to get smarter here. - vec!(), + vec![], Component::UnresolvedInferenceVariable(..) => - vec!(), + vec![], } }) .collect() @@ -497,7 +498,7 @@ impl<'a, 'gcx, 'tcx> WfPredicates<'a, 'gcx, 'tcx> { let explicit_bound = data.region_bound; for implicit_bound in implicit_bounds { - let cause = self.cause(traits::ReferenceOutlivesReferent(ty)); + let cause = self.cause(traits::ObjectTypeBound(ty, explicit_bound)); let outlives = ty::Binder(ty::OutlivesPredicate(explicit_bound, implicit_bound)); self.out.push(traits::Obligation::new(cause, outlives.to_predicate())); } diff --git a/src/librustc/util/common.rs b/src/librustc/util/common.rs index 78f20b77f3..7cd5fd78df 100644 --- a/src/librustc/util/common.rs +++ b/src/librustc/util/common.rs @@ -75,6 +75,26 @@ pub fn duration_to_secs_str(dur: Duration) -> String { format!("{:.3}", secs) } +pub fn to_readable_str(mut val: usize) -> String { + let mut groups = vec![]; + loop { + let group = val % 1000; + + val /= 1000; + + if val == 0 { + groups.push(format!("{}", group)); + break + } else { + groups.push(format!("{:03}", group)); + } + } + + groups.reverse(); + + groups.join("_") +} + pub fn record_time(accu: &Cell, f: F) -> T where F: FnOnce() -> T, { @@ -264,3 +284,17 @@ pub fn path2cstr(p: &Path) -> CString { pub fn path2cstr(p: &Path) -> CString { CString::new(p.to_str().unwrap()).unwrap() } + + +#[test] +fn test_to_readable_str() { + assert_eq!("0", to_readable_str(0)); + assert_eq!("1", to_readable_str(1)); + assert_eq!("99", to_readable_str(99)); + assert_eq!("999", to_readable_str(999)); + assert_eq!("1_000", to_readable_str(1_000)); + assert_eq!("1_001", to_readable_str(1_001)); + assert_eq!("999_999", to_readable_str(999_999)); + assert_eq!("1_000_000", to_readable_str(1_000_000)); + assert_eq!("1_234_567", to_readable_str(1_234_567)); +} diff --git a/src/librustc/util/ppaux.rs b/src/librustc/util/ppaux.rs index 312cab2454..31304fb7b4 100644 --- a/src/librustc/util/ppaux.rs +++ b/src/librustc/util/ppaux.rs @@ -9,13 +9,13 @@ // except according to those terms. use hir::def_id::DefId; -use ty::subst::{self, Subst, Substs}; use hir::map::definitions::DefPathData; +use ty::subst::{self, Subst}; use ty::{BrAnon, BrEnv, BrFresh, BrNamed}; use ty::{TyBool, TyChar, TyAdt}; use ty::{TyError, TyStr, TyArray, TySlice, TyFloat, TyFnDef, TyFnPtr}; use ty::{TyParam, TyRawPtr, TyRef, TyNever, TyTuple}; -use ty::TyClosure; +use ty::{TyClosure, TyProjection, TyAnon}; use ty::{TyBox, TyTrait, TyInt, TyUint, TyInfer}; use ty::{self, Ty, TyCtxt, TypeFoldable}; use ty::fold::{TypeFolder, TypeVisitor}; @@ -447,32 +447,9 @@ impl<'tcx, 'container> fmt::Debug for ty::AdtDefData<'tcx, 'container> { } } -impl<'tcx> fmt::Debug for ty::adjustment::AutoAdjustment<'tcx> { +impl<'tcx> fmt::Debug for ty::adjustment::Adjustment<'tcx> { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - match *self { - ty::adjustment::AdjustNeverToAny(ref target) => { - write!(f, "AdjustNeverToAny({:?})", target) - } - ty::adjustment::AdjustReifyFnPointer => { - write!(f, "AdjustReifyFnPointer") - } - ty::adjustment::AdjustUnsafeFnPointer => { - write!(f, "AdjustUnsafeFnPointer") - } - ty::adjustment::AdjustMutToConstPointer => { - write!(f, "AdjustMutToConstPointer") - } - ty::adjustment::AdjustDerefRef(ref data) => { - write!(f, "{:?}", data) - } - } - } -} - -impl<'tcx> fmt::Debug for ty::adjustment::AutoDerefRef<'tcx> { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - write!(f, "AutoDerefRef({}, unsize={:?}, {:?})", - self.autoderefs, self.unsize, self.autoref) + write!(f, "{:?} -> {}", self.kind, self.target) } } @@ -908,14 +885,14 @@ impl<'tcx> fmt::Display for ty::TypeVariants<'tcx> { }) } TyTrait(ref data) => write!(f, "{}", data), - ty::TyProjection(ref data) => write!(f, "{}", data), - ty::TyAnon(def_id, substs) => { + TyProjection(ref data) => write!(f, "{}", data), + TyAnon(def_id, substs) => { ty::tls::with(|tcx| { // Grab the "TraitA + TraitB" from `impl TraitA + TraitB`, // by looking up the projections associated with the def_id. let item_predicates = tcx.lookup_predicates(def_id); let substs = tcx.lift(&substs).unwrap_or_else(|| { - Substs::empty(tcx) + tcx.intern_substs(&[]) }); let bounds = item_predicates.instantiate(tcx, substs); diff --git a/src/librustc_back/lib.rs b/src/librustc_back/lib.rs index 92b03b5ca2..da5f787bdf 100644 --- a/src/librustc_back/lib.rs +++ b/src/librustc_back/lib.rs @@ -36,17 +36,43 @@ #![feature(rand)] #![feature(rustc_private)] #![feature(staged_api)] -#![feature(step_by)] #![cfg_attr(stage0, feature(question_mark))] -#![cfg_attr(test, feature(test, rand))] +#![cfg_attr(test, feature(rand))] extern crate syntax; extern crate libc; extern crate serialize; #[macro_use] extern crate log; +extern crate serialize as rustc_serialize; // used by deriving + pub mod tempdir; -pub mod sha2; pub mod target; pub mod slice; pub mod dynamic_lib; + +use serialize::json::{Json, ToJson}; + +#[derive(Clone, Copy, Debug, PartialEq, Hash, RustcEncodable, RustcDecodable)] +pub enum PanicStrategy { + Unwind, + Abort, +} + +impl PanicStrategy { + pub fn desc(&self) -> &str { + match *self { + PanicStrategy::Unwind => "unwind", + PanicStrategy::Abort => "abort", + } + } +} + +impl ToJson for PanicStrategy { + fn to_json(&self) -> Json { + match *self { + PanicStrategy::Abort => "abort".to_json(), + PanicStrategy::Unwind => "unwind".to_json(), + } + } +} diff --git a/src/librustc_back/sha2.rs b/src/librustc_back/sha2.rs deleted file mode 100644 index 97fb39c17e..0000000000 --- a/src/librustc_back/sha2.rs +++ /dev/null @@ -1,679 +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. - -//! This module implements only the Sha256 function since that is all that is needed for internal -//! use. This implementation is not intended for external use or for any use where security is -//! important. - -use serialize::hex::ToHex; - -/// Write a u32 into a vector, which must be 4 bytes long. The value is written in big-endian -/// format. -fn write_u32_be(dst: &mut[u8], input: u32) { - dst[0] = (input >> 24) as u8; - dst[1] = (input >> 16) as u8; - dst[2] = (input >> 8) as u8; - dst[3] = input as u8; -} - -/// Read the value of a vector of bytes as a u32 value in big-endian format. -fn read_u32_be(input: &[u8]) -> u32 { - (input[0] as u32) << 24 | - (input[1] as u32) << 16 | - (input[2] as u32) << 8 | - (input[3] as u32) -} - -/// Read a vector of bytes into a vector of u32s. The values are read in big-endian format. -fn read_u32v_be(dst: &mut[u32], input: &[u8]) { - assert!(dst.len() * 4 == input.len()); - let mut pos = 0; - for chunk in input.chunks(4) { - dst[pos] = read_u32_be(chunk); - pos += 1; - } -} - -trait ToBits: Sized { - /// Convert the value in bytes to the number of bits, a tuple where the 1st item is the - /// high-order value and the 2nd item is the low order value. - fn to_bits(self) -> (Self, Self); -} - -impl ToBits for u64 { - fn to_bits(self) -> (u64, u64) { - (self >> 61, self << 3) - } -} - -/// Adds the specified number of bytes to the bit count. panic!() if this would cause numeric -/// overflow. -fn add_bytes_to_bits(bits: u64, bytes: u64) -> u64 { - let (new_high_bits, new_low_bits) = bytes.to_bits(); - - if new_high_bits > 0 { - panic!("numeric overflow occurred.") - } - - match bits.checked_add(new_low_bits) { - Some(x) => x, - None => panic!("numeric overflow occurred.") - } -} - -/// A FixedBuffer, likes its name implies, is a fixed size buffer. When the buffer becomes full, it -/// must be processed. The input() method takes care of processing and then clearing the buffer -/// automatically. However, other methods do not and require the caller to process the buffer. Any -/// method that modifies the buffer directory or provides the caller with bytes that can be modified -/// results in those bytes being marked as used by the buffer. -trait FixedBuffer { - /// Input a vector of bytes. If the buffer becomes full, process it with the provided - /// function and then clear the buffer. - fn input(&mut self, input: &[u8], func: F) where - F: FnMut(&[u8]); - - /// Reset the buffer. - fn reset(&mut self); - - /// Zero the buffer up until the specified index. The buffer position currently must not be - /// greater than that index. - fn zero_until(&mut self, idx: usize); - - /// Get a slice of the buffer of the specified size. There must be at least that many bytes - /// remaining in the buffer. - fn next<'s>(&'s mut self, len: usize) -> &'s mut [u8]; - - /// Get the current buffer. The buffer must already be full. This clears the buffer as well. - fn full_buffer<'s>(&'s mut self) -> &'s [u8]; - - /// Get the current position of the buffer. - fn position(&self) -> usize; - - /// Get the number of bytes remaining in the buffer until it is full. - fn remaining(&self) -> usize; - - /// Get the size of the buffer - fn size(&self) -> usize; -} - -/// A FixedBuffer of 64 bytes useful for implementing Sha256 which has a 64 byte blocksize. -struct FixedBuffer64 { - buffer: [u8; 64], - buffer_idx: usize, -} - -impl FixedBuffer64 { - /// Create a new FixedBuffer64 - fn new() -> FixedBuffer64 { - FixedBuffer64 { - buffer: [0; 64], - buffer_idx: 0 - } - } -} - -impl FixedBuffer for FixedBuffer64 { - fn input(&mut self, input: &[u8], mut func: F) where - F: FnMut(&[u8]), - { - let mut i = 0; - - let size = self.size(); - - // If there is already data in the buffer, copy as much as we can into it and process - // the data if the buffer becomes full. - if self.buffer_idx != 0 { - let buffer_remaining = size - self.buffer_idx; - if input.len() >= buffer_remaining { - self.buffer[self.buffer_idx..size] - .copy_from_slice(&input[..buffer_remaining]); - self.buffer_idx = 0; - func(&self.buffer); - i += buffer_remaining; - } else { - self.buffer[self.buffer_idx..self.buffer_idx + input.len()] - .copy_from_slice(input); - self.buffer_idx += input.len(); - return; - } - } - - // While we have at least a full buffer size chunk's worth of data, process that data - // without copying it into the buffer - while input.len() - i >= size { - func(&input[i..i + size]); - i += size; - } - - // Copy any input data into the buffer. At this point in the method, the amount of - // data left in the input vector will be less than the buffer size and the buffer will - // be empty. - let input_remaining = input.len() - i; - self.buffer[..input_remaining].copy_from_slice(&input[i..]); - self.buffer_idx += input_remaining; - } - - fn reset(&mut self) { - self.buffer_idx = 0; - } - - fn zero_until(&mut self, idx: usize) { - assert!(idx >= self.buffer_idx); - for slot in self.buffer[self.buffer_idx..idx].iter_mut() { - *slot = 0; - } - self.buffer_idx = idx; - } - - fn next<'s>(&'s mut self, len: usize) -> &'s mut [u8] { - self.buffer_idx += len; - &mut self.buffer[self.buffer_idx - len..self.buffer_idx] - } - - fn full_buffer<'s>(&'s mut self) -> &'s [u8] { - assert!(self.buffer_idx == 64); - self.buffer_idx = 0; - &self.buffer[..64] - } - - fn position(&self) -> usize { self.buffer_idx } - - fn remaining(&self) -> usize { 64 - self.buffer_idx } - - fn size(&self) -> usize { 64 } -} - -/// The StandardPadding trait adds a method useful for Sha256 to a FixedBuffer struct. -trait StandardPadding { - /// Add padding to the buffer. The buffer must not be full when this method is called and is - /// guaranteed to have exactly rem remaining bytes when it returns. If there are not at least - /// rem bytes available, the buffer will be zero padded, processed, cleared, and then filled - /// with zeros again until only rem bytes are remaining. - fn standard_padding(&mut self, rem: usize, func: F) where F: FnMut(&[u8]); -} - -impl StandardPadding for T { - fn standard_padding(&mut self, rem: usize, mut func: F) where F: FnMut(&[u8]) { - let size = self.size(); - - self.next(1)[0] = 128; - - if self.remaining() < rem { - self.zero_until(size); - func(self.full_buffer()); - } - - self.zero_until(size - rem); - } -} - -/// The Digest trait specifies an interface common to digest functions, such as SHA-1 and the SHA-2 -/// family of digest functions. -pub trait Digest { - /// Provide message data. - /// - /// # Arguments - /// - /// * input - A vector of message data - fn input(&mut self, input: &[u8]); - - /// Retrieve the digest result. This method may be called multiple times. - /// - /// # Arguments - /// - /// * out - the vector to hold the result. Must be large enough to contain output_bits(). - fn result(&mut self, out: &mut [u8]); - - /// Reset the digest. This method must be called after result() and before supplying more - /// data. - fn reset(&mut self); - - /// Get the output size in bits. - fn output_bits(&self) -> usize; - - /// Convenience function that feeds a string into a digest. - /// - /// # Arguments - /// - /// * `input` The string to feed into the digest - fn input_str(&mut self, input: &str) { - self.input(input.as_bytes()); - } - - /// Convenience function that retrieves the result of a digest as a - /// newly allocated vec of bytes. - fn result_bytes(&mut self) -> Vec { - let mut buf = vec![0; (self.output_bits()+7)/8]; - self.result(&mut buf); - buf - } - - /// Convenience function that retrieves the result of a digest as a - /// String in hexadecimal format. - fn result_str(&mut self) -> String { - self.result_bytes().to_hex().to_string() - } -} - -// A structure that represents that state of a digest computation for the SHA-2 512 family of digest -// functions -struct Engine256State { - h0: u32, - h1: u32, - h2: u32, - h3: u32, - h4: u32, - h5: u32, - h6: u32, - h7: u32, -} - -impl Engine256State { - fn new(h: &[u32; 8]) -> Engine256State { - Engine256State { - h0: h[0], - h1: h[1], - h2: h[2], - h3: h[3], - h4: h[4], - h5: h[5], - h6: h[6], - h7: h[7] - } - } - - fn reset(&mut self, h: &[u32; 8]) { - self.h0 = h[0]; - self.h1 = h[1]; - self.h2 = h[2]; - self.h3 = h[3]; - self.h4 = h[4]; - self.h5 = h[5]; - self.h6 = h[6]; - self.h7 = h[7]; - } - - fn process_block(&mut self, data: &[u8]) { - fn ch(x: u32, y: u32, z: u32) -> u32 { - ((x & y) ^ ((!x) & z)) - } - - fn maj(x: u32, y: u32, z: u32) -> u32 { - ((x & y) ^ (x & z) ^ (y & z)) - } - - fn sum0(x: u32) -> u32 { - ((x >> 2) | (x << 30)) ^ ((x >> 13) | (x << 19)) ^ ((x >> 22) | (x << 10)) - } - - fn sum1(x: u32) -> u32 { - ((x >> 6) | (x << 26)) ^ ((x >> 11) | (x << 21)) ^ ((x >> 25) | (x << 7)) - } - - fn sigma0(x: u32) -> u32 { - ((x >> 7) | (x << 25)) ^ ((x >> 18) | (x << 14)) ^ (x >> 3) - } - - fn sigma1(x: u32) -> u32 { - ((x >> 17) | (x << 15)) ^ ((x >> 19) | (x << 13)) ^ (x >> 10) - } - - let mut a = self.h0; - let mut b = self.h1; - let mut c = self.h2; - let mut d = self.h3; - let mut e = self.h4; - let mut f = self.h5; - let mut g = self.h6; - let mut h = self.h7; - - let mut w = [0; 64]; - - // Sha-512 and Sha-256 use basically the same calculations which are implemented - // by these macros. Inlining the calculations seems to result in better generated code. - macro_rules! schedule_round { ($t:expr) => ( - w[$t] = sigma1(w[$t - 2]).wrapping_add(w[$t - 7]) - .wrapping_add(sigma0(w[$t - 15])).wrapping_add(w[$t - 16]); - ) - } - - macro_rules! sha2_round { - ($A:ident, $B:ident, $C:ident, $D:ident, - $E:ident, $F:ident, $G:ident, $H:ident, $K:ident, $t:expr) => ( - { - $H = $H.wrapping_add(sum1($E)).wrapping_add(ch($E, $F, $G)) - .wrapping_add($K[$t]).wrapping_add(w[$t]); - $D = $D.wrapping_add($H); - $H = $H.wrapping_add(sum0($A)).wrapping_add(maj($A, $B, $C)); - } - ) - } - - read_u32v_be(&mut w[0..16], data); - - // Putting the message schedule inside the same loop as the round calculations allows for - // the compiler to generate better code. - for t in (0..48).step_by(8) { - schedule_round!(t + 16); - schedule_round!(t + 17); - schedule_round!(t + 18); - schedule_round!(t + 19); - schedule_round!(t + 20); - schedule_round!(t + 21); - schedule_round!(t + 22); - schedule_round!(t + 23); - - sha2_round!(a, b, c, d, e, f, g, h, K32, t); - sha2_round!(h, a, b, c, d, e, f, g, K32, t + 1); - sha2_round!(g, h, a, b, c, d, e, f, K32, t + 2); - sha2_round!(f, g, h, a, b, c, d, e, K32, t + 3); - sha2_round!(e, f, g, h, a, b, c, d, K32, t + 4); - sha2_round!(d, e, f, g, h, a, b, c, K32, t + 5); - sha2_round!(c, d, e, f, g, h, a, b, K32, t + 6); - sha2_round!(b, c, d, e, f, g, h, a, K32, t + 7); - } - - for t in (48..64).step_by(8) { - sha2_round!(a, b, c, d, e, f, g, h, K32, t); - sha2_round!(h, a, b, c, d, e, f, g, K32, t + 1); - sha2_round!(g, h, a, b, c, d, e, f, K32, t + 2); - sha2_round!(f, g, h, a, b, c, d, e, K32, t + 3); - sha2_round!(e, f, g, h, a, b, c, d, K32, t + 4); - sha2_round!(d, e, f, g, h, a, b, c, K32, t + 5); - sha2_round!(c, d, e, f, g, h, a, b, K32, t + 6); - sha2_round!(b, c, d, e, f, g, h, a, K32, t + 7); - } - - self.h0 = self.h0.wrapping_add(a); - self.h1 = self.h1.wrapping_add(b); - self.h2 = self.h2.wrapping_add(c); - self.h3 = self.h3.wrapping_add(d); - self.h4 = self.h4.wrapping_add(e); - self.h5 = self.h5.wrapping_add(f); - self.h6 = self.h6.wrapping_add(g); - self.h7 = self.h7.wrapping_add(h); - } -} - -static K32: [u32; 64] = [ - 0x428a2f98, 0x71374491, 0xb5c0fbcf, 0xe9b5dba5, - 0x3956c25b, 0x59f111f1, 0x923f82a4, 0xab1c5ed5, - 0xd807aa98, 0x12835b01, 0x243185be, 0x550c7dc3, - 0x72be5d74, 0x80deb1fe, 0x9bdc06a7, 0xc19bf174, - 0xe49b69c1, 0xefbe4786, 0x0fc19dc6, 0x240ca1cc, - 0x2de92c6f, 0x4a7484aa, 0x5cb0a9dc, 0x76f988da, - 0x983e5152, 0xa831c66d, 0xb00327c8, 0xbf597fc7, - 0xc6e00bf3, 0xd5a79147, 0x06ca6351, 0x14292967, - 0x27b70a85, 0x2e1b2138, 0x4d2c6dfc, 0x53380d13, - 0x650a7354, 0x766a0abb, 0x81c2c92e, 0x92722c85, - 0xa2bfe8a1, 0xa81a664b, 0xc24b8b70, 0xc76c51a3, - 0xd192e819, 0xd6990624, 0xf40e3585, 0x106aa070, - 0x19a4c116, 0x1e376c08, 0x2748774c, 0x34b0bcb5, - 0x391c0cb3, 0x4ed8aa4a, 0x5b9cca4f, 0x682e6ff3, - 0x748f82ee, 0x78a5636f, 0x84c87814, 0x8cc70208, - 0x90befffa, 0xa4506ceb, 0xbef9a3f7, 0xc67178f2 -]; - -// A structure that keeps track of the state of the Sha-256 operation and contains the logic -// necessary to perform the final calculations. -struct Engine256 { - length_bits: u64, - buffer: FixedBuffer64, - state: Engine256State, - finished: bool, -} - -impl Engine256 { - fn new(h: &[u32; 8]) -> Engine256 { - Engine256 { - length_bits: 0, - buffer: FixedBuffer64::new(), - state: Engine256State::new(h), - finished: false - } - } - - fn reset(&mut self, h: &[u32; 8]) { - self.length_bits = 0; - self.buffer.reset(); - self.state.reset(h); - self.finished = false; - } - - fn input(&mut self, input: &[u8]) { - assert!(!self.finished); - // Assumes that input.len() can be converted to u64 without overflow - self.length_bits = add_bytes_to_bits(self.length_bits, input.len() as u64); - let self_state = &mut self.state; - self.buffer.input(input, |input: &[u8]| { self_state.process_block(input) }); - } - - fn finish(&mut self) { - if !self.finished { - let self_state = &mut self.state; - self.buffer.standard_padding(8, |input: &[u8]| { self_state.process_block(input) }); - write_u32_be(self.buffer.next(4), (self.length_bits >> 32) as u32 ); - write_u32_be(self.buffer.next(4), self.length_bits as u32); - self_state.process_block(self.buffer.full_buffer()); - - self.finished = true; - } - } -} - -/// The SHA-256 hash algorithm -pub struct Sha256 { - engine: Engine256 -} - -impl Sha256 { - /// Construct a new instance of a SHA-256 digest. - /// Do not – under any circumstances – use this where timing attacks might be possible! - pub fn new() -> Sha256 { - Sha256 { - engine: Engine256::new(&H256) - } - } -} - -impl Digest for Sha256 { - fn input(&mut self, d: &[u8]) { - self.engine.input(d); - } - - fn result(&mut self, out: &mut [u8]) { - self.engine.finish(); - - write_u32_be(&mut out[0..4], self.engine.state.h0); - write_u32_be(&mut out[4..8], self.engine.state.h1); - write_u32_be(&mut out[8..12], self.engine.state.h2); - write_u32_be(&mut out[12..16], self.engine.state.h3); - write_u32_be(&mut out[16..20], self.engine.state.h4); - write_u32_be(&mut out[20..24], self.engine.state.h5); - write_u32_be(&mut out[24..28], self.engine.state.h6); - write_u32_be(&mut out[28..32], self.engine.state.h7); - } - - fn reset(&mut self) { - self.engine.reset(&H256); - } - - fn output_bits(&self) -> usize { 256 } -} - -static H256: [u32; 8] = [ - 0x6a09e667, - 0xbb67ae85, - 0x3c6ef372, - 0xa54ff53a, - 0x510e527f, - 0x9b05688c, - 0x1f83d9ab, - 0x5be0cd19 -]; - -#[cfg(test)] -mod tests { - #![allow(deprecated)] - extern crate rand; - - use self::rand::Rng; - use self::rand::isaac::IsaacRng; - use serialize::hex::FromHex; - use std::u64; - use super::{Digest, Sha256}; - - // A normal addition - no overflow occurs - #[test] - fn test_add_bytes_to_bits_ok() { - 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); - } - - struct Test { - input: String, - output_str: String, - } - - fn test_hash(sh: &mut D, tests: &[Test]) { - // Test that it works when accepting the message all at once - for t in tests { - sh.reset(); - sh.input_str(&t.input); - let out_str = sh.result_str(); - assert!(out_str == t.output_str); - } - - // Test that it works when accepting the message in pieces - for t in tests { - sh.reset(); - let len = t.input.len(); - let mut left = len; - while left > 0 { - let take = (left + 1) / 2; - sh.input_str(&t.input[len - left..take + len - left]); - left = left - take; - } - let out_str = sh.result_str(); - assert!(out_str == t.output_str); - } - } - - #[test] - fn test_sha256() { - // Examples from wikipedia - let wikipedia_tests = vec!( - Test { - input: "".to_string(), - output_str: "e3b0c44298fc1c149afb\ - f4c8996fb92427ae41e4649b934ca495991b7852b855".to_string() - }, - Test { - input: "The quick brown fox jumps over the lazy \ - dog".to_string(), - output_str: "d7a8fbb307d7809469ca\ - 9abcb0082e4f8d5651e46d3cdb762d02d0bf37c9e592".to_string() - }, - Test { - input: "The quick brown fox jumps over the lazy \ - dog.".to_string(), - output_str: "ef537f25c895bfa78252\ - 6529a9b63d97aa631564d5d789c2b765448c8635fb6c".to_string() - }); - - let tests = wikipedia_tests; - - let mut sh: Box<_> = box Sha256::new(); - - test_hash(&mut *sh, &tests); - } - - /// Feed 1,000,000 'a's into the digest with varying input sizes and check that the result is - /// correct. - fn test_digest_1million_random(digest: &mut D, blocksize: usize, expected: &str) { - let total_size = 1000000; - let buffer = vec![b'a'; blocksize * 2]; - let mut rng = IsaacRng::new_unseeded(); - let mut count = 0; - - digest.reset(); - - while count < total_size { - let next: usize = rng.gen_range(0, 2 * blocksize + 1); - let remaining = total_size - count; - let size = if next > remaining { remaining } else { next }; - digest.input(&buffer[..size]); - count += size; - } - - let result_str = digest.result_str(); - let result_bytes = digest.result_bytes(); - - assert_eq!(expected, result_str); - - let expected_vec: Vec = expected.from_hex() - .unwrap() - .into_iter() - .collect(); - assert_eq!(expected_vec, result_bytes); - } - - #[test] - fn test_1million_random_sha256() { - let mut sh = Sha256::new(); - test_digest_1million_random( - &mut sh, - 64, - "cdc76e5c9914fb9281a1c7e284d73e67f1809a48a497200e046d39ccc7112cd0"); - } -} - -#[cfg(test)] -mod bench { - extern crate test; - use self::test::Bencher; - use super::{Sha256, Digest}; - - #[bench] - pub fn sha256_10(b: &mut Bencher) { - let mut sh = Sha256::new(); - let bytes = [1; 10]; - b.iter(|| { - sh.input(&bytes); - }); - b.bytes = bytes.len() as u64; - } - - #[bench] - pub fn sha256_1k(b: &mut Bencher) { - let mut sh = Sha256::new(); - let bytes = [1; 1024]; - b.iter(|| { - sh.input(&bytes); - }); - b.bytes = bytes.len() as u64; - } - - #[bench] - pub fn sha256_64k(b: &mut Bencher) { - let mut sh = Sha256::new(); - let bytes = [1; 65536]; - b.iter(|| { - sh.input(&bytes); - }); - b.bytes = bytes.len() as u64; - } -} diff --git a/src/librustc_back/target/aarch64_apple_ios.rs b/src/librustc_back/target/aarch64_apple_ios.rs index 660ed0ac7b..5ef7935914 100644 --- a/src/librustc_back/target/aarch64_apple_ios.rs +++ b/src/librustc_back/target/aarch64_apple_ios.rs @@ -25,7 +25,8 @@ pub fn target() -> TargetResult { options: TargetOptions { features: "+neon,+fp-armv8,+cyclone".to_string(), eliminate_frame_pointer: false, - max_atomic_width: 128, + max_atomic_width: Some(128), + abi_blacklist: super::arm_base::abi_blacklist(), .. base }, }) diff --git a/src/librustc_back/target/aarch64_linux_android.rs b/src/librustc_back/target/aarch64_linux_android.rs index 7f54dab5b5..140195c780 100644 --- a/src/librustc_back/target/aarch64_linux_android.rs +++ b/src/librustc_back/target/aarch64_linux_android.rs @@ -8,11 +8,11 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -use target::{Target, TargetResult}; +use target::{Target, TargetOptions, TargetResult}; pub fn target() -> TargetResult { let mut base = super::android_base::opts(); - base.max_atomic_width = 128; + base.max_atomic_width = Some(128); // As documented in http://developer.android.com/ndk/guides/cpu-features.html // the neon (ASIMD) and FP must exist on all android aarch64 targets. base.features = "+neon,+fp-armv8".to_string(); @@ -25,6 +25,9 @@ pub fn target() -> TargetResult { target_os: "android".to_string(), target_env: "".to_string(), target_vendor: "unknown".to_string(), - options: base, + options: TargetOptions { + abi_blacklist: super::arm_base::abi_blacklist(), + .. base + }, }) } diff --git a/src/librustc_back/target/aarch64_unknown_fuchsia.rs b/src/librustc_back/target/aarch64_unknown_fuchsia.rs new file mode 100644 index 0000000000..6ba1732e67 --- /dev/null +++ b/src/librustc_back/target/aarch64_unknown_fuchsia.rs @@ -0,0 +1,31 @@ +// Copyright 2016 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +use target::{Target, TargetOptions, TargetResult}; + +pub fn target() -> TargetResult { + let mut base = super::fuchsia_base::opts(); + base.max_atomic_width = Some(128); + + Ok(Target { + llvm_target: "aarch64-unknown-fuchsia".to_string(), + target_endian: "little".to_string(), + target_pointer_width: "64".to_string(), + data_layout: "e-m:e-i8:8:32-i16:16:32-i64:64-i128:128-n32:64-S128".to_string(), + arch: "aarch64".to_string(), + target_os: "fuchsia".to_string(), + target_env: "".to_string(), + target_vendor: "unknown".to_string(), + options: TargetOptions { + abi_blacklist: super::arm_base::abi_blacklist(), + .. base + }, + }) +} diff --git a/src/librustc_back/target/aarch64_unknown_linux_gnu.rs b/src/librustc_back/target/aarch64_unknown_linux_gnu.rs index cca965f9d4..5f6335d405 100644 --- a/src/librustc_back/target/aarch64_unknown_linux_gnu.rs +++ b/src/librustc_back/target/aarch64_unknown_linux_gnu.rs @@ -8,11 +8,15 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -use target::{Target, TargetResult}; +use target::{Target, TargetOptions, TargetResult}; pub fn target() -> TargetResult { let mut base = super::linux_base::opts(); - base.max_atomic_width = 128; + base.max_atomic_width = Some(128); + + // see #36994 + base.exe_allocation_crate = "alloc_system".to_string(); + Ok(Target { llvm_target: "aarch64-unknown-linux-gnu".to_string(), target_endian: "little".to_string(), @@ -22,6 +26,9 @@ pub fn target() -> TargetResult { arch: "aarch64".to_string(), target_os: "linux".to_string(), target_vendor: "unknown".to_string(), - options: base, + options: TargetOptions { + abi_blacklist: super::arm_base::abi_blacklist(), + .. base + }, }) } diff --git a/src/librustc_back/target/arm_base.rs b/src/librustc_back/target/arm_base.rs new file mode 100644 index 0000000000..ad132c27cb --- /dev/null +++ b/src/librustc_back/target/arm_base.rs @@ -0,0 +1,16 @@ +// Copyright 2016 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +use syntax::abi::Abi; + +// All the calling conventions trigger an assertion(Unsupported calling convention) in llvm on arm +pub fn abi_blacklist() -> Vec { + vec![Abi::Stdcall, Abi::Fastcall, Abi::Vectorcall, Abi::Win64, Abi::SysV64] +} diff --git a/src/librustc_back/target/arm_linux_androideabi.rs b/src/librustc_back/target/arm_linux_androideabi.rs index f3a18b13c6..c7d2df4344 100644 --- a/src/librustc_back/target/arm_linux_androideabi.rs +++ b/src/librustc_back/target/arm_linux_androideabi.rs @@ -8,12 +8,12 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -use target::{Target, TargetResult}; +use target::{Target, TargetOptions, TargetResult}; pub fn target() -> TargetResult { let mut base = super::android_base::opts(); base.features = "+v7,+vfp3,+d16".to_string(); - base.max_atomic_width = 64; + base.max_atomic_width = Some(64); Ok(Target { llvm_target: "arm-linux-androideabi".to_string(), @@ -24,6 +24,9 @@ pub fn target() -> TargetResult { target_os: "android".to_string(), target_env: "".to_string(), target_vendor: "unknown".to_string(), - options: base, + options: TargetOptions { + abi_blacklist: super::arm_base::abi_blacklist(), + .. base + }, }) } diff --git a/src/librustc_back/target/arm_unknown_linux_gnueabi.rs b/src/librustc_back/target/arm_unknown_linux_gnueabi.rs index e666a8460e..77d35edfbd 100644 --- a/src/librustc_back/target/arm_unknown_linux_gnueabi.rs +++ b/src/librustc_back/target/arm_unknown_linux_gnueabi.rs @@ -12,7 +12,7 @@ use target::{Target, TargetOptions, TargetResult}; pub fn target() -> TargetResult { let mut base = super::linux_base::opts(); - base.max_atomic_width = 64; + base.max_atomic_width = Some(64); Ok(Target { llvm_target: "arm-unknown-linux-gnueabi".to_string(), target_endian: "little".to_string(), @@ -25,6 +25,7 @@ pub fn target() -> TargetResult { options: TargetOptions { features: "+v6".to_string(), + abi_blacklist: super::arm_base::abi_blacklist(), .. base }, }) diff --git a/src/librustc_back/target/arm_unknown_linux_gnueabihf.rs b/src/librustc_back/target/arm_unknown_linux_gnueabihf.rs index d65c89abc2..b183412be1 100644 --- a/src/librustc_back/target/arm_unknown_linux_gnueabihf.rs +++ b/src/librustc_back/target/arm_unknown_linux_gnueabihf.rs @@ -12,7 +12,7 @@ use target::{Target, TargetOptions, TargetResult}; pub fn target() -> TargetResult { let mut base = super::linux_base::opts(); - base.max_atomic_width = 64; + base.max_atomic_width = Some(64); Ok(Target { llvm_target: "arm-unknown-linux-gnueabihf".to_string(), target_endian: "little".to_string(), @@ -25,6 +25,7 @@ pub fn target() -> TargetResult { options: TargetOptions { features: "+v6,+vfp2".to_string(), + abi_blacklist: super::arm_base::abi_blacklist(), .. base } }) diff --git a/src/librustc_back/target/arm_unknown_linux_musleabi.rs b/src/librustc_back/target/arm_unknown_linux_musleabi.rs index 028c91eada..261d4353c7 100644 --- a/src/librustc_back/target/arm_unknown_linux_musleabi.rs +++ b/src/librustc_back/target/arm_unknown_linux_musleabi.rs @@ -8,7 +8,7 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -use target::{Target, TargetResult}; +use target::{Target, TargetOptions, TargetResult}; pub fn target() -> TargetResult { let mut base = super::linux_musl_base::opts(); @@ -16,7 +16,7 @@ pub fn target() -> TargetResult { // Most of these settings are copied from the arm_unknown_linux_gnueabi // target. base.features = "+v6".to_string(); - base.max_atomic_width = 64; + base.max_atomic_width = Some(64); Ok(Target { // It's important we use "gnueabi" and not "musleabi" here. LLVM uses it // to determine the calling convention and float ABI, and it doesn't @@ -29,6 +29,9 @@ pub fn target() -> TargetResult { target_os: "linux".to_string(), target_env: "musl".to_string(), target_vendor: "unknown".to_string(), - options: base, + options: TargetOptions { + abi_blacklist: super::arm_base::abi_blacklist(), + .. base + }, }) } diff --git a/src/librustc_back/target/arm_unknown_linux_musleabihf.rs b/src/librustc_back/target/arm_unknown_linux_musleabihf.rs index c7dda186f4..1443dcf5ba 100644 --- a/src/librustc_back/target/arm_unknown_linux_musleabihf.rs +++ b/src/librustc_back/target/arm_unknown_linux_musleabihf.rs @@ -8,7 +8,7 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -use target::{Target, TargetResult}; +use target::{Target, TargetOptions, TargetResult}; pub fn target() -> TargetResult { let mut base = super::linux_musl_base::opts(); @@ -16,7 +16,7 @@ pub fn target() -> TargetResult { // Most of these settings are copied from the arm_unknown_linux_gnueabihf // target. base.features = "+v6,+vfp2".to_string(); - base.max_atomic_width = 64; + base.max_atomic_width = Some(64); Ok(Target { // It's important we use "gnueabihf" and not "musleabihf" here. LLVM // uses it to determine the calling convention and float ABI, and it @@ -29,6 +29,9 @@ pub fn target() -> TargetResult { target_os: "linux".to_string(), target_env: "musl".to_string(), target_vendor: "unknown".to_string(), - options: base, + options: TargetOptions { + abi_blacklist: super::arm_base::abi_blacklist(), + .. base + }, }) } diff --git a/src/librustc_back/target/armv7_apple_ios.rs b/src/librustc_back/target/armv7_apple_ios.rs index 71533a09b1..9e9c443930 100644 --- a/src/librustc_back/target/armv7_apple_ios.rs +++ b/src/librustc_back/target/armv7_apple_ios.rs @@ -24,7 +24,8 @@ pub fn target() -> TargetResult { target_vendor: "apple".to_string(), options: TargetOptions { features: "+v7,+vfp3,+neon".to_string(), - max_atomic_width: 64, + max_atomic_width: Some(64), + abi_blacklist: super::arm_base::abi_blacklist(), .. base } }) diff --git a/src/librustc_back/target/armv7_linux_androideabi.rs b/src/librustc_back/target/armv7_linux_androideabi.rs index 1c59262e04..42f0deaa3f 100644 --- a/src/librustc_back/target/armv7_linux_androideabi.rs +++ b/src/librustc_back/target/armv7_linux_androideabi.rs @@ -8,12 +8,12 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -use target::{Target, TargetResult}; +use target::{Target, TargetOptions, TargetResult}; pub fn target() -> TargetResult { let mut base = super::android_base::opts(); base.features = "+v7,+thumb2,+vfp3,+d16".to_string(); - base.max_atomic_width = 64; + base.max_atomic_width = Some(64); Ok(Target { llvm_target: "armv7-none-linux-android".to_string(), @@ -24,6 +24,9 @@ pub fn target() -> TargetResult { target_os: "android".to_string(), target_env: "".to_string(), target_vendor: "unknown".to_string(), - options: base, + options: TargetOptions { + abi_blacklist: super::arm_base::abi_blacklist(), + .. base + }, }) } diff --git a/src/librustc_back/target/armv7_unknown_linux_gnueabihf.rs b/src/librustc_back/target/armv7_unknown_linux_gnueabihf.rs index 7e0306a03e..96ccedd5be 100644 --- a/src/librustc_back/target/armv7_unknown_linux_gnueabihf.rs +++ b/src/librustc_back/target/armv7_unknown_linux_gnueabihf.rs @@ -24,9 +24,10 @@ pub fn target() -> TargetResult { options: TargetOptions { // Info about features at https://wiki.debian.org/ArmHardFloatPort - features: "+v7,+vfp3,+d16,+thumb2".to_string(), + features: "+v7,+vfp3,+d16,+thumb2,-neon".to_string(), cpu: "generic".to_string(), - max_atomic_width: 64, + max_atomic_width: Some(64), + abi_blacklist: super::arm_base::abi_blacklist(), .. base } }) diff --git a/src/librustc_back/target/armv7_unknown_linux_musleabihf.rs b/src/librustc_back/target/armv7_unknown_linux_musleabihf.rs index e40704e5d4..8f66e6a4f5 100644 --- a/src/librustc_back/target/armv7_unknown_linux_musleabihf.rs +++ b/src/librustc_back/target/armv7_unknown_linux_musleabihf.rs @@ -8,7 +8,7 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -use target::{Target, TargetResult}; +use target::{Target, TargetOptions, TargetResult}; pub fn target() -> TargetResult { let mut base = super::linux_musl_base::opts(); @@ -17,7 +17,7 @@ pub fn target() -> TargetResult { // target. base.features = "+v7,+vfp3,+neon".to_string(); base.cpu = "cortex-a8".to_string(); - base.max_atomic_width = 64; + base.max_atomic_width = Some(64); Ok(Target { // It's important we use "gnueabihf" and not "musleabihf" here. LLVM // uses it to determine the calling convention and float ABI, and LLVM @@ -30,6 +30,9 @@ pub fn target() -> TargetResult { target_os: "linux".to_string(), target_env: "musl".to_string(), target_vendor: "unknown".to_string(), - options: base, + options: TargetOptions { + abi_blacklist: super::arm_base::abi_blacklist(), + .. base + }, }) } diff --git a/src/librustc_back/target/armv7s_apple_ios.rs b/src/librustc_back/target/armv7s_apple_ios.rs index f24b996991..6edde6e73e 100644 --- a/src/librustc_back/target/armv7s_apple_ios.rs +++ b/src/librustc_back/target/armv7s_apple_ios.rs @@ -24,7 +24,8 @@ pub fn target() -> TargetResult { target_vendor: "apple".to_string(), options: TargetOptions { features: "+v7,+vfp4,+neon".to_string(), - max_atomic_width: 64, + max_atomic_width: Some(64), + abi_blacklist: super::arm_base::abi_blacklist(), .. base } }) diff --git a/src/librustc_back/target/asmjs_unknown_emscripten.rs b/src/librustc_back/target/asmjs_unknown_emscripten.rs index 9ccfdbb129..d86a9b0932 100644 --- a/src/librustc_back/target/asmjs_unknown_emscripten.rs +++ b/src/librustc_back/target/asmjs_unknown_emscripten.rs @@ -21,7 +21,8 @@ pub fn target() -> Result { linker_is_gnu: true, allow_asm: false, obj_is_bitcode: true, - max_atomic_width: 32, + max_atomic_width: Some(32), + post_link_args: vec!["-s".to_string(), "ERROR_ON_UNDEFINED_SYMBOLS=1".to_string()], .. Default::default() }; Ok(Target { diff --git a/src/librustc_back/target/dragonfly_base.rs b/src/librustc_back/target/dragonfly_base.rs index e2c4003a8b..7555181a15 100644 --- a/src/librustc_back/target/dragonfly_base.rs +++ b/src/librustc_back/target/dragonfly_base.rs @@ -17,7 +17,7 @@ pub fn opts() -> TargetOptions { executables: true, linker_is_gnu: true, has_rpath: true, - pre_link_args: vec!( + pre_link_args: vec![ // GNU-style linkers will use this to omit linking to libraries // which don't actually fulfill any relocations, but only for // libraries which follow this flag. Thus, use it before @@ -26,7 +26,7 @@ pub fn opts() -> TargetOptions { // Always enable NX protection when it is available "-Wl,-z,noexecstack".to_string(), - ), + ], position_independent_executables: true, exe_allocation_crate: super::maybe_jemalloc(), .. Default::default() diff --git a/src/librustc_back/target/freebsd_base.rs b/src/librustc_back/target/freebsd_base.rs index e2c4003a8b..7555181a15 100644 --- a/src/librustc_back/target/freebsd_base.rs +++ b/src/librustc_back/target/freebsd_base.rs @@ -17,7 +17,7 @@ pub fn opts() -> TargetOptions { executables: true, linker_is_gnu: true, has_rpath: true, - pre_link_args: vec!( + pre_link_args: vec![ // GNU-style linkers will use this to omit linking to libraries // which don't actually fulfill any relocations, but only for // libraries which follow this flag. Thus, use it before @@ -26,7 +26,7 @@ pub fn opts() -> TargetOptions { // Always enable NX protection when it is available "-Wl,-z,noexecstack".to_string(), - ), + ], position_independent_executables: true, exe_allocation_crate: super::maybe_jemalloc(), .. Default::default() diff --git a/src/librustc_back/target/fuchsia_base.rs b/src/librustc_back/target/fuchsia_base.rs new file mode 100644 index 0000000000..69546684cb --- /dev/null +++ b/src/librustc_back/target/fuchsia_base.rs @@ -0,0 +1,39 @@ +// 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 target::TargetOptions; +use std::default::Default; + +pub fn opts() -> TargetOptions { + TargetOptions { + dynamic_linking: true, + executables: true, + linker_is_gnu: true, + has_rpath: true, + pre_link_args: vec![ + // We want to be able to strip as much executable code as possible + // from the linker command line, and this flag indicates to the + // linker that it can avoid linking in dynamic libraries that don't + // actually satisfy any symbols up to that point (as with many other + // resolutions the linker does). This option only applies to all + // following libraries so we're sure to pass it as one of the first + // arguments. + // FIXME: figure out whether these linker args are desirable + //"-Wl,--as-needed".to_string(), + + // Always enable NX protection when it is available + //"-Wl,-z,noexecstack".to_string(), + ], + position_independent_executables: true, + exe_allocation_crate: "alloc_system".to_string(), + has_elf_tls: true, + .. Default::default() + } +} diff --git a/src/librustc_back/target/i386_apple_ios.rs b/src/librustc_back/target/i386_apple_ios.rs index 94146fe9d9..319ada4f8e 100644 --- a/src/librustc_back/target/i386_apple_ios.rs +++ b/src/librustc_back/target/i386_apple_ios.rs @@ -23,7 +23,7 @@ pub fn target() -> TargetResult { target_env: "".to_string(), target_vendor: "apple".to_string(), options: TargetOptions { - max_atomic_width: 64, + max_atomic_width: Some(64), .. base } }) diff --git a/src/librustc_back/target/i686_apple_darwin.rs b/src/librustc_back/target/i686_apple_darwin.rs index 4876a3489d..d3b09d9a0f 100644 --- a/src/librustc_back/target/i686_apple_darwin.rs +++ b/src/librustc_back/target/i686_apple_darwin.rs @@ -13,7 +13,7 @@ use target::{Target, TargetResult}; pub fn target() -> TargetResult { let mut base = super::apple_base::opts(); base.cpu = "yonah".to_string(); - base.max_atomic_width = 64; + base.max_atomic_width = Some(64); base.pre_link_args.push("-m32".to_string()); Ok(Target { diff --git a/src/librustc_back/target/i686_linux_android.rs b/src/librustc_back/target/i686_linux_android.rs index 1de629238a..a2c007d496 100644 --- a/src/librustc_back/target/i686_linux_android.rs +++ b/src/librustc_back/target/i686_linux_android.rs @@ -13,7 +13,7 @@ use target::{Target, TargetResult}; pub fn target() -> TargetResult { let mut base = super::android_base::opts(); - base.max_atomic_width = 64; + base.max_atomic_width = Some(64); // http://developer.android.com/ndk/guides/abis.html#x86 base.cpu = "pentiumpro".to_string(); diff --git a/src/librustc_back/target/i686_pc_windows_gnu.rs b/src/librustc_back/target/i686_pc_windows_gnu.rs index 2c19b8109c..0c2c5433e6 100644 --- a/src/librustc_back/target/i686_pc_windows_gnu.rs +++ b/src/librustc_back/target/i686_pc_windows_gnu.rs @@ -13,7 +13,7 @@ use target::{Target, TargetResult}; pub fn target() -> TargetResult { let mut base = super::windows_base::opts(); base.cpu = "pentium4".to_string(); - base.max_atomic_width = 64; + base.max_atomic_width = Some(64); // Mark all dynamic libraries and executables as compatible with the larger 4GiB address // space available to x86 Windows binaries on x86_64. diff --git a/src/librustc_back/target/i686_pc_windows_msvc.rs b/src/librustc_back/target/i686_pc_windows_msvc.rs index cb02fcc308..2290d2057f 100644 --- a/src/librustc_back/target/i686_pc_windows_msvc.rs +++ b/src/librustc_back/target/i686_pc_windows_msvc.rs @@ -13,7 +13,7 @@ use target::{Target, TargetResult}; pub fn target() -> TargetResult { let mut base = super::windows_msvc_base::opts(); base.cpu = "pentium4".to_string(); - base.max_atomic_width = 64; + base.max_atomic_width = Some(64); // Mark all dynamic libraries and executables as compatible with the larger 4GiB address // space available to x86 Windows binaries on x86_64. diff --git a/src/librustc_back/target/i686_unknown_dragonfly.rs b/src/librustc_back/target/i686_unknown_dragonfly.rs index f96ec004b4..d8f8431e66 100644 --- a/src/librustc_back/target/i686_unknown_dragonfly.rs +++ b/src/librustc_back/target/i686_unknown_dragonfly.rs @@ -13,7 +13,7 @@ use target::{Target, TargetResult}; pub fn target() -> TargetResult { let mut base = super::dragonfly_base::opts(); base.cpu = "pentium4".to_string(); - base.max_atomic_width = 64; + base.max_atomic_width = Some(64); base.pre_link_args.push("-m32".to_string()); Ok(Target { diff --git a/src/librustc_back/target/i686_unknown_freebsd.rs b/src/librustc_back/target/i686_unknown_freebsd.rs index 3489ecfe61..ddbc74f25c 100644 --- a/src/librustc_back/target/i686_unknown_freebsd.rs +++ b/src/librustc_back/target/i686_unknown_freebsd.rs @@ -13,7 +13,7 @@ use target::{Target, TargetResult}; pub fn target() -> TargetResult { let mut base = super::freebsd_base::opts(); base.cpu = "pentium4".to_string(); - base.max_atomic_width = 64; + base.max_atomic_width = Some(64); base.pre_link_args.push("-m32".to_string()); Ok(Target { diff --git a/src/librustc_back/target/i686_unknown_haiku.rs b/src/librustc_back/target/i686_unknown_haiku.rs index 862016704f..9078206c9e 100644 --- a/src/librustc_back/target/i686_unknown_haiku.rs +++ b/src/librustc_back/target/i686_unknown_haiku.rs @@ -13,7 +13,7 @@ use target::{Target, TargetResult}; pub fn target() -> TargetResult { let mut base = super::haiku_base::opts(); base.cpu = "pentium4".to_string(); - base.max_atomic_width = 64; + base.max_atomic_width = Some(64); base.pre_link_args.push("-m32".to_string()); Ok(Target { diff --git a/src/librustc_back/target/i686_unknown_linux_gnu.rs b/src/librustc_back/target/i686_unknown_linux_gnu.rs index f2e865c015..bf9c28b0c1 100644 --- a/src/librustc_back/target/i686_unknown_linux_gnu.rs +++ b/src/librustc_back/target/i686_unknown_linux_gnu.rs @@ -13,7 +13,7 @@ use target::{Target, TargetResult}; pub fn target() -> TargetResult { let mut base = super::linux_base::opts(); base.cpu = "pentium4".to_string(); - base.max_atomic_width = 64; + base.max_atomic_width = Some(64); base.pre_link_args.push("-m32".to_string()); Ok(Target { diff --git a/src/librustc_back/target/i686_unknown_linux_musl.rs b/src/librustc_back/target/i686_unknown_linux_musl.rs index a0a8de46e2..3d563fa6e5 100644 --- a/src/librustc_back/target/i686_unknown_linux_musl.rs +++ b/src/librustc_back/target/i686_unknown_linux_musl.rs @@ -13,7 +13,7 @@ use target::{Target, TargetResult}; pub fn target() -> TargetResult { let mut base = super::linux_musl_base::opts(); base.cpu = "pentium4".to_string(); - base.max_atomic_width = 64; + base.max_atomic_width = Some(64); base.pre_link_args.push("-m32".to_string()); base.pre_link_args.push("-Wl,-melf_i386".to_string()); diff --git a/src/librustc_back/target/le32_unknown_nacl.rs b/src/librustc_back/target/le32_unknown_nacl.rs index 9ba6591f58..891e7dda14 100644 --- a/src/librustc_back/target/le32_unknown_nacl.rs +++ b/src/librustc_back/target/le32_unknown_nacl.rs @@ -15,16 +15,16 @@ pub fn target() -> TargetResult { linker: "pnacl-clang".to_string(), ar: "pnacl-ar".to_string(), - pre_link_args: vec!("--pnacl-exceptions=sjlj".to_string(), + pre_link_args: vec!["--pnacl-exceptions=sjlj".to_string(), "--target=le32-unknown-nacl".to_string(), - "-Wl,--start-group".to_string()), - post_link_args: vec!("-Wl,--end-group".to_string()), + "-Wl,--start-group".to_string()], + post_link_args: vec!["-Wl,--end-group".to_string()], dynamic_linking: false, executables: true, exe_suffix: ".pexe".to_string(), linker_is_gnu: true, allow_asm: false, - max_atomic_width: 32, + max_atomic_width: Some(32), .. Default::default() }; Ok(Target { diff --git a/src/librustc_back/target/mips64_unknown_linux_gnuabi64.rs b/src/librustc_back/target/mips64_unknown_linux_gnuabi64.rs index 7e45b32065..c284840ecb 100644 --- a/src/librustc_back/target/mips64_unknown_linux_gnuabi64.rs +++ b/src/librustc_back/target/mips64_unknown_linux_gnuabi64.rs @@ -24,7 +24,11 @@ pub fn target() -> TargetResult { // NOTE(mips64r2) matches C toolchain cpu: "mips64r2".to_string(), features: "+mips64r2".to_string(), - max_atomic_width: 64, + max_atomic_width: Some(64), + + // see #36994 + exe_allocation_crate: "alloc_system".to_string(), + ..super::linux_base::opts() }, }) diff --git a/src/librustc_back/target/mips64el_unknown_linux_gnuabi64.rs b/src/librustc_back/target/mips64el_unknown_linux_gnuabi64.rs index 338a5da1e1..17895836fe 100644 --- a/src/librustc_back/target/mips64el_unknown_linux_gnuabi64.rs +++ b/src/librustc_back/target/mips64el_unknown_linux_gnuabi64.rs @@ -24,7 +24,11 @@ pub fn target() -> TargetResult { // NOTE(mips64r2) matches C toolchain cpu: "mips64r2".to_string(), features: "+mips64r2".to_string(), - max_atomic_width: 64, + max_atomic_width: Some(64), + + // see #36994 + exe_allocation_crate: "alloc_system".to_string(), + ..super::linux_base::opts() }, }) diff --git a/src/librustc_back/target/mips_unknown_linux_gnu.rs b/src/librustc_back/target/mips_unknown_linux_gnu.rs index ab967f6b40..a6d8fae253 100644 --- a/src/librustc_back/target/mips_unknown_linux_gnu.rs +++ b/src/librustc_back/target/mips_unknown_linux_gnu.rs @@ -23,7 +23,11 @@ pub fn target() -> TargetResult { options: TargetOptions { cpu: "mips32r2".to_string(), features: "+mips32r2".to_string(), - max_atomic_width: 32, + max_atomic_width: Some(32), + + // see #36994 + exe_allocation_crate: "alloc_system".to_string(), + ..super::linux_base::opts() }, }) diff --git a/src/librustc_back/target/mips_unknown_linux_musl.rs b/src/librustc_back/target/mips_unknown_linux_musl.rs index 4a69bce53b..e4a6d2a55d 100644 --- a/src/librustc_back/target/mips_unknown_linux_musl.rs +++ b/src/librustc_back/target/mips_unknown_linux_musl.rs @@ -23,7 +23,11 @@ pub fn target() -> TargetResult { options: TargetOptions { cpu: "mips32r2".to_string(), features: "+mips32r2,+soft-float".to_string(), - max_atomic_width: 32, + max_atomic_width: Some(32), + + // see #36994 + exe_allocation_crate: "alloc_system".to_string(), + ..super::linux_base::opts() } }) diff --git a/src/librustc_back/target/mips_unknown_linux_uclibc.rs b/src/librustc_back/target/mips_unknown_linux_uclibc.rs index 529bd31039..ccc64ea393 100644 --- a/src/librustc_back/target/mips_unknown_linux_uclibc.rs +++ b/src/librustc_back/target/mips_unknown_linux_uclibc.rs @@ -23,7 +23,11 @@ pub fn target() -> TargetResult { options: TargetOptions { cpu: "mips32r2".to_string(), features: "+mips32r2,+soft-float".to_string(), - max_atomic_width: 32, + max_atomic_width: Some(32), + + // see #36994 + exe_allocation_crate: "alloc_system".to_string(), + ..super::linux_base::opts() }, }) diff --git a/src/librustc_back/target/mipsel_unknown_linux_gnu.rs b/src/librustc_back/target/mipsel_unknown_linux_gnu.rs index b66fb62cd5..9b8b1d5713 100644 --- a/src/librustc_back/target/mipsel_unknown_linux_gnu.rs +++ b/src/librustc_back/target/mipsel_unknown_linux_gnu.rs @@ -24,7 +24,11 @@ pub fn target() -> TargetResult { options: TargetOptions { cpu: "mips32".to_string(), features: "+mips32".to_string(), - max_atomic_width: 32, + max_atomic_width: Some(32), + + // see #36994 + exe_allocation_crate: "alloc_system".to_string(), + ..super::linux_base::opts() }, }) diff --git a/src/librustc_back/target/mipsel_unknown_linux_musl.rs b/src/librustc_back/target/mipsel_unknown_linux_musl.rs index a0524e5e76..5693bddd04 100644 --- a/src/librustc_back/target/mipsel_unknown_linux_musl.rs +++ b/src/librustc_back/target/mipsel_unknown_linux_musl.rs @@ -23,7 +23,11 @@ pub fn target() -> TargetResult { options: TargetOptions { cpu: "mips32".to_string(), features: "+mips32,+soft-float".to_string(), - max_atomic_width: 32, + max_atomic_width: Some(32), + + // see #36994 + exe_allocation_crate: "alloc_system".to_string(), + ..super::linux_base::opts() } }) diff --git a/src/librustc_back/target/mipsel_unknown_linux_uclibc.rs b/src/librustc_back/target/mipsel_unknown_linux_uclibc.rs index 1040a0fbe1..3acade5a47 100644 --- a/src/librustc_back/target/mipsel_unknown_linux_uclibc.rs +++ b/src/librustc_back/target/mipsel_unknown_linux_uclibc.rs @@ -24,7 +24,11 @@ pub fn target() -> TargetResult { options: TargetOptions { cpu: "mips32".to_string(), features: "+mips32,+soft-float".to_string(), - max_atomic_width: 32, + max_atomic_width: Some(32), + + // see #36994 + exe_allocation_crate: "alloc_system".to_string(), + ..super::linux_base::opts() }, }) diff --git a/src/librustc_back/target/mod.rs b/src/librustc_back/target/mod.rs index 087078021a..4d9315a1a3 100644 --- a/src/librustc_back/target/mod.rs +++ b/src/librustc_back/target/mod.rs @@ -48,11 +48,14 @@ use serialize::json::{Json, ToJson}; use std::collections::BTreeMap; use std::default::Default; use std::io::prelude::*; -use syntax::abi::Abi; +use syntax::abi::{Abi, lookup as lookup_abi}; + +use PanicStrategy; mod android_base; mod apple_base; mod apple_ios_base; +mod arm_base; mod bitrig_base; mod dragonfly_base; mod freebsd_base; @@ -64,11 +67,13 @@ mod netbsd_base; mod solaris_base; mod windows_base; mod windows_msvc_base; +mod thumb_base; +mod fuchsia_base; pub type TargetResult = Result; macro_rules! supported_targets { - ( $(($triple:expr, $module:ident)),+ ) => ( + ( $(($triple:expr, $module:ident),)+ ) => ( $(mod $module;)* /// List of supported targets @@ -166,12 +171,15 @@ supported_targets! { ("x86_64-unknown-netbsd", x86_64_unknown_netbsd), ("x86_64-rumprun-netbsd", x86_64_rumprun_netbsd), - ("i686_unknown_haiku", i686_unknown_haiku), - ("x86_64_unknown_haiku", x86_64_unknown_haiku), + ("i686-unknown-haiku", i686_unknown_haiku), + ("x86_64-unknown-haiku", x86_64_unknown_haiku), ("x86_64-apple-darwin", x86_64_apple_darwin), ("i686-apple-darwin", i686_apple_darwin), + ("aarch64-unknown-fuchsia", aarch64_unknown_fuchsia), + ("x86_64-unknown-fuchsia", x86_64_unknown_fuchsia), + ("i386-apple-ios", i386_apple_ios), ("x86_64-apple-ios", x86_64_apple_ios), ("aarch64-apple-ios", aarch64_apple_ios), @@ -188,7 +196,13 @@ supported_targets! { ("i586-pc-windows-msvc", i586_pc_windows_msvc), ("le32-unknown-nacl", le32_unknown_nacl), - ("asmjs-unknown-emscripten", asmjs_unknown_emscripten) + ("asmjs-unknown-emscripten", asmjs_unknown_emscripten), + ("wasm32-unknown-emscripten", wasm32_unknown_emscripten), + + ("thumbv6m-none-eabi", thumbv6m_none_eabi), + ("thumbv7m-none-eabi", thumbv7m_none_eabi), + ("thumbv7em-none-eabi", thumbv7em_none_eabi), + ("thumbv7em-none-eabihf", thumbv7em_none_eabihf), } /// Everything `rustc` knows about how to compile for a specific target. @@ -344,9 +358,15 @@ pub struct TargetOptions { // will 'just work'. pub obj_is_bitcode: bool, - /// Maximum integer size in bits that this target can perform atomic - /// operations on. - pub max_atomic_width: u64, + /// Don't use this field; instead use the `.max_atomic_width()` method. + pub max_atomic_width: Option, + + /// Panic strategy: "unwind" or "abort" + pub panic_strategy: PanicStrategy, + + /// A blacklist of ABIs unsupported by the current target. Note that generic + /// ABIs are considered to be supported on all platforms and cannot be blacklisted. + pub abi_blacklist: Vec, } impl Default for TargetOptions { @@ -395,7 +415,9 @@ impl Default for TargetOptions { allow_asm: true, has_elf_tls: false, obj_is_bitcode: false, - max_atomic_width: 0, + max_atomic_width: None, + panic_strategy: PanicStrategy::Unwind, + abi_blacklist: vec![], } } } @@ -415,6 +437,16 @@ impl Target { } } + /// Maximum integer size in bits that this target can perform atomic + /// operations on. + pub fn max_atomic_width(&self) -> u64 { + self.options.max_atomic_width.unwrap_or(self.target_pointer_width.parse().unwrap()) + } + + pub fn is_abi_supported(&self, abi: Abi) -> bool { + abi.generic() || !self.options.abi_blacklist.contains(&abi) + } + /// Load a target descriptor from a JSON object. pub fn from_json(obj: Json) -> TargetResult { // While ugly, this code must remain this way to retain @@ -453,9 +485,6 @@ impl Target { options: Default::default(), }; - // Default max-atomic-width to target-pointer-width - base.options.max_atomic_width = base.target_pointer_width.parse().unwrap(); - macro_rules! key { ($key_name:ident) => ( { let name = (stringify!($key_name)).replace("_", "-"); @@ -468,11 +497,24 @@ impl Target { .map(|o| o.as_boolean() .map(|s| base.options.$key_name = s)); } ); - ($key_name:ident, u64) => ( { + ($key_name:ident, Option) => ( { let name = (stringify!($key_name)).replace("_", "-"); obj.find(&name[..]) .map(|o| o.as_u64() - .map(|s| base.options.$key_name = s)); + .map(|s| base.options.$key_name = Some(s))); + } ); + ($key_name:ident, PanicStrategy) => ( { + let name = (stringify!($key_name)).replace("_", "-"); + obj.find(&name[..]).and_then(|o| o.as_string().and_then(|s| { + match s { + "unwind" => base.options.$key_name = PanicStrategy::Unwind, + "abort" => base.options.$key_name = PanicStrategy::Abort, + _ => return Some(Err(format!("'{}' is not a valid value for \ + panic-strategy. Use 'unwind' or 'abort'.", + s))), + } + Some(Ok(())) + })).unwrap_or(Ok(())) } ); ($key_name:ident, list) => ( { let name = (stringify!($key_name)).replace("_", "-"); @@ -533,7 +575,24 @@ impl Target { key!(exe_allocation_crate); key!(has_elf_tls, bool); key!(obj_is_bitcode, bool); - key!(max_atomic_width, u64); + key!(max_atomic_width, Option); + try!(key!(panic_strategy, PanicStrategy)); + + if let Some(array) = obj.find("abi-blacklist").and_then(Json::as_array) { + for name in array.iter().filter_map(|abi| abi.as_string()) { + match lookup_abi(name) { + Some(abi) => { + if abi.generic() { + return Err(format!("The ABI \"{}\" is considered to be supported on \ + all targets and cannot be blacklisted", abi)) + } + + base.options.abi_blacklist.push(abi) + } + None => return Err(format!("Unknown ABI \"{}\" in target specification", name)) + } + } + } Ok(base) } @@ -676,6 +735,13 @@ impl ToJson for Target { target_option_val!(has_elf_tls); target_option_val!(obj_is_bitcode); target_option_val!(max_atomic_width); + target_option_val!(panic_strategy); + + if default.abi_blacklist != self.options.abi_blacklist { + d.insert("abi-blacklist".to_string(), self.options.abi_blacklist.iter() + .map(Abi::name).map(|name| name.to_json()) + .collect::>().to_json()); + } Json::Object(d) } diff --git a/src/librustc_back/target/netbsd_base.rs b/src/librustc_back/target/netbsd_base.rs index cc03ed56aa..6e038a7ed5 100644 --- a/src/librustc_back/target/netbsd_base.rs +++ b/src/librustc_back/target/netbsd_base.rs @@ -17,7 +17,7 @@ pub fn opts() -> TargetOptions { executables: true, linker_is_gnu: true, has_rpath: true, - pre_link_args: vec!( + pre_link_args: vec![ // GNU-style linkers will use this to omit linking to libraries // which don't actually fulfill any relocations, but only for // libraries which follow this flag. Thus, use it before @@ -26,7 +26,7 @@ pub fn opts() -> TargetOptions { // Always enable NX protection when it is available "-Wl,-z,noexecstack".to_string(), - ), + ], position_independent_executables: true, .. Default::default() } diff --git a/src/librustc_back/target/openbsd_base.rs b/src/librustc_back/target/openbsd_base.rs index 7afdfcd691..90e6631841 100644 --- a/src/librustc_back/target/openbsd_base.rs +++ b/src/librustc_back/target/openbsd_base.rs @@ -17,7 +17,7 @@ pub fn opts() -> TargetOptions { executables: true, linker_is_gnu: true, has_rpath: true, - pre_link_args: vec!( + pre_link_args: vec![ // GNU-style linkers will use this to omit linking to libraries // which don't actually fulfill any relocations, but only for // libraries which follow this flag. Thus, use it before @@ -26,7 +26,7 @@ pub fn opts() -> TargetOptions { // Always enable NX protection when it is available "-Wl,-z,noexecstack".to_string(), - ), + ], position_independent_executables: true, exe_allocation_crate: "alloc_system".to_string(), .. Default::default() diff --git a/src/librustc_back/target/powerpc64_unknown_linux_gnu.rs b/src/librustc_back/target/powerpc64_unknown_linux_gnu.rs index 1c04e76341..909c5488dc 100644 --- a/src/librustc_back/target/powerpc64_unknown_linux_gnu.rs +++ b/src/librustc_back/target/powerpc64_unknown_linux_gnu.rs @@ -14,7 +14,10 @@ pub fn target() -> TargetResult { let mut base = super::linux_base::opts(); base.cpu = "ppc64".to_string(); base.pre_link_args.push("-m64".to_string()); - base.max_atomic_width = 64; + base.max_atomic_width = Some(64); + + // see #36994 + base.exe_allocation_crate = "alloc_system".to_string(); Ok(Target { llvm_target: "powerpc64-unknown-linux-gnu".to_string(), diff --git a/src/librustc_back/target/powerpc64le_unknown_linux_gnu.rs b/src/librustc_back/target/powerpc64le_unknown_linux_gnu.rs index 906e28d2f2..a692346ca0 100644 --- a/src/librustc_back/target/powerpc64le_unknown_linux_gnu.rs +++ b/src/librustc_back/target/powerpc64le_unknown_linux_gnu.rs @@ -14,7 +14,10 @@ pub fn target() -> TargetResult { let mut base = super::linux_base::opts(); base.cpu = "ppc64le".to_string(); base.pre_link_args.push("-m64".to_string()); - base.max_atomic_width = 64; + base.max_atomic_width = Some(64); + + // see #36994 + base.exe_allocation_crate = "alloc_system".to_string(); Ok(Target { llvm_target: "powerpc64le-unknown-linux-gnu".to_string(), diff --git a/src/librustc_back/target/powerpc_unknown_linux_gnu.rs b/src/librustc_back/target/powerpc_unknown_linux_gnu.rs index aebf9cd687..284772c433 100644 --- a/src/librustc_back/target/powerpc_unknown_linux_gnu.rs +++ b/src/librustc_back/target/powerpc_unknown_linux_gnu.rs @@ -13,7 +13,10 @@ use target::{Target, TargetResult}; pub fn target() -> TargetResult { let mut base = super::linux_base::opts(); base.pre_link_args.push("-m32".to_string()); - base.max_atomic_width = 32; + base.max_atomic_width = Some(32); + + // see #36994 + base.exe_allocation_crate = "alloc_system".to_string(); Ok(Target { llvm_target: "powerpc-unknown-linux-gnu".to_string(), diff --git a/src/librustc_back/target/s390x_unknown_linux_gnu.rs b/src/librustc_back/target/s390x_unknown_linux_gnu.rs index 79f2d290e3..6e2dd6cd67 100644 --- a/src/librustc_back/target/s390x_unknown_linux_gnu.rs +++ b/src/librustc_back/target/s390x_unknown_linux_gnu.rs @@ -18,7 +18,7 @@ pub fn target() -> TargetResult { // cabi_s390x.rs are for now hard-coded to assume the no-vector ABI. // Pass the -vector feature string to LLVM to respect this assumption. base.features = "-vector".to_string(); - base.max_atomic_width = 64; + base.max_atomic_width = Some(64); Ok(Target { llvm_target: "s390x-unknown-linux-gnu".to_string(), diff --git a/src/librustc_back/target/thumb_base.rs b/src/librustc_back/target/thumb_base.rs new file mode 100644 index 0000000000..6bb496649a --- /dev/null +++ b/src/librustc_back/target/thumb_base.rs @@ -0,0 +1,58 @@ +// Copyright 2016 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +// These 4 `thumbv*` targets cover the ARM Cortex-M family of processors which are widely used in +// microcontrollers. Namely, all these processors: +// +// - Cortex-M0 +// - Cortex-M0+ +// - Cortex-M1 +// - Cortex-M3 +// - Cortex-M4(F) +// - Cortex-M7(F) +// +// We have opted for 4 targets instead of one target per processor (e.g. `cortex-m0`, `cortex-m3`, +// etc) because the differences between some processors like the cortex-m0 and cortex-m1 are almost +// non-existent from the POV of codegen so it doesn't make sense to have separate targets for them. +// And if differences exist between two processors under the same target, rustc flags can be used to +// optimize for one processor or the other. +// +// Also, we have not chosen a single target (`arm-none-eabi`) like GCC does because this makes +// difficult to integrate Rust code and C code. Targeting the Cortex-M4 requires different gcc flags +// than the ones you would use for the Cortex-M0 and with a single target it'd be impossible to +// differentiate one processor from the other. +// +// About arm vs thumb in the name. The Cortex-M devices only support the Thumb instruction set, +// which is more compact (higher code density), and not the ARM instruction set. That's why LLVM +// triples use thumb instead of arm. We follow suit because having thumb in the name let us +// differentiate these targets from our other `arm(v7)-*-*-gnueabi(hf)` targets in the context of +// build scripts / gcc flags. + +use PanicStrategy; +use std::default::Default; +use target::TargetOptions; + +pub fn opts() -> TargetOptions { + // See rust-lang/rfcs#1645 for a discussion about these defaults + TargetOptions { + executables: true, + // In 99%+ of cases, we want to use the `arm-none-eabi-gcc` compiler (there aren't many + // options around) + linker: "arm-none-eabi-gcc".to_string(), + // Because these devices have very little resources having an unwinder is too onerous so we + // default to "abort" because the "unwind" strategy is very rare. + panic_strategy: PanicStrategy::Abort, + // Similarly, one almost always never wants to use relocatable code because of the extra + // costs it involves. + relocation_model: "static".to_string(), + abi_blacklist: super::arm_base::abi_blacklist(), + .. Default::default() + } +} diff --git a/src/librustc_back/target/thumbv6m_none_eabi.rs b/src/librustc_back/target/thumbv6m_none_eabi.rs new file mode 100644 index 0000000000..6c22f98538 --- /dev/null +++ b/src/librustc_back/target/thumbv6m_none_eabi.rs @@ -0,0 +1,36 @@ +// Copyright 2016 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +// Targets the Cortex-M0, Cortex-M0+ and Cortex-M1 processors (ARMv6-M architecture) + +use target::{Target, TargetOptions, TargetResult}; + +pub fn target() -> TargetResult { + Ok(Target { + llvm_target: "thumbv6m-none-eabi".to_string(), + target_endian: "little".to_string(), + target_pointer_width: "32".to_string(), + data_layout: "e-m:e-p:32:32-i64:64-v128:64:128-a:0:32-n32-S64".to_string(), + arch: "arm".to_string(), + target_os: "none".to_string(), + target_env: "".to_string(), + target_vendor: "".to_string(), + + options: TargetOptions { + // The ARMv6-M architecture doesn't support unaligned loads/stores so we disable them + // with +strict-align. + features: "+strict-align".to_string(), + // There are no atomic instructions available in the instruction set of the ARMv6-M + // architecture + max_atomic_width: Some(0), + .. super::thumb_base::opts() + } + }) +} diff --git a/src/librustc_back/target/thumbv7em_none_eabi.rs b/src/librustc_back/target/thumbv7em_none_eabi.rs new file mode 100644 index 0000000000..ddad4e3624 --- /dev/null +++ b/src/librustc_back/target/thumbv7em_none_eabi.rs @@ -0,0 +1,40 @@ +// Copyright 2016 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +// Targets the Cortex-M4 and Cortex-M7 processors (ARMv7E-M) +// +// This target assumes that the device doesn't have a FPU (Floating Point Unit) and lowers all the +// floating point operations to software routines (intrinsics). +// +// As such, this target uses the "soft" calling convention (ABI) where floating point values are +// passed to/from subroutines via general purpose registers (R0, R1, etc.). +// +// To opt-in to hardware accelerated floating point operations, you can use, for example, +// `-C target-feature=+vfp4` or `-C target-cpu=cortex-m4`. + +use target::{Target, TargetOptions, TargetResult}; + +pub fn target() -> TargetResult { + Ok(Target { + llvm_target: "thumbv7em-none-eabi".to_string(), + target_endian: "little".to_string(), + target_pointer_width: "32".to_string(), + data_layout: "e-m:e-p:32:32-i64:64-v128:64:128-a:0:32-n32-S64".to_string(), + arch: "arm".to_string(), + target_os: "none".to_string(), + target_env: "".to_string(), + target_vendor: "".to_string(), + + options: TargetOptions { + max_atomic_width: Some(32), + .. super::thumb_base::opts() + }, + }) +} diff --git a/src/librustc_back/target/thumbv7em_none_eabihf.rs b/src/librustc_back/target/thumbv7em_none_eabihf.rs new file mode 100644 index 0000000000..a9fac48e8e --- /dev/null +++ b/src/librustc_back/target/thumbv7em_none_eabihf.rs @@ -0,0 +1,49 @@ +// Copyright 2016 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +// Targets the Cortex-M4F and Cortex-M7F processors (ARMv7E-M) +// +// This target assumes that the device does have a FPU (Floating Point Unit) and lowers all (single +// precision) floating point operations to hardware instructions. +// +// Additionally, this target uses the "hard" floating convention (ABI) where floating point values +// are passed to/from subroutines via FPU registers (S0, S1, D0, D1, etc.). +// +// To opt into double precision hardware support, use the `-C target-feature=-fp-only-sp` flag. + +use target::{Target, TargetOptions, TargetResult}; + +pub fn target() -> TargetResult { + Ok(Target { + llvm_target: "thumbv7em-none-eabihf".to_string(), + target_endian: "little".to_string(), + target_pointer_width: "32".to_string(), + data_layout: "e-m:e-p:32:32-i64:64-v128:64:128-a:0:32-n32-S64".to_string(), + arch: "arm".to_string(), + target_os: "none".to_string(), + target_env: "".to_string(), + target_vendor: "".to_string(), + + options: TargetOptions { + // `+vfp4` is the lowest common denominator between the Cortex-M4 (vfp4-16) and the + // Cortex-M7 (vfp5) + // `+d16` both the Cortex-M4 and the Cortex-M7 only have 16 double-precision registers + // available + // `+fp-only-sp` The Cortex-M4 only supports single precision floating point operations + // whereas in the Cortex-M7 double precision is optional + // + // Reference: + // ARMv7-M Architecture Reference Manual - A2.5 The optional floating-point extension + features: "+vfp4,+d16,+fp-only-sp".to_string(), + max_atomic_width: Some(32), + .. super::thumb_base::opts() + } + }) +} diff --git a/src/librustc_back/target/thumbv7m_none_eabi.rs b/src/librustc_back/target/thumbv7m_none_eabi.rs new file mode 100644 index 0000000000..ed61dd0459 --- /dev/null +++ b/src/librustc_back/target/thumbv7m_none_eabi.rs @@ -0,0 +1,31 @@ +// Copyright 2016 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +// Targets the Cortex-M3 processor (ARMv7-M) + +use target::{Target, TargetOptions, TargetResult}; + +pub fn target() -> TargetResult { + Ok(Target { + llvm_target: "thumbv7m-none-eabi".to_string(), + target_endian: "little".to_string(), + target_pointer_width: "32".to_string(), + data_layout: "e-m:e-p:32:32-i64:64-v128:64:128-a:0:32-n32-S64".to_string(), + arch: "arm".to_string(), + target_os: "none".to_string(), + target_env: "".to_string(), + target_vendor: "".to_string(), + + options: TargetOptions { + max_atomic_width: Some(32), + .. super::thumb_base::opts() + }, + }) +} diff --git a/src/librustc_back/target/wasm32_unknown_emscripten.rs b/src/librustc_back/target/wasm32_unknown_emscripten.rs new file mode 100644 index 0000000000..77ab4fcae7 --- /dev/null +++ b/src/librustc_back/target/wasm32_unknown_emscripten.rs @@ -0,0 +1,42 @@ +// 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 super::{Target, TargetOptions}; + +pub fn target() -> Result { + let opts = TargetOptions { + linker: "emcc".to_string(), + ar: "emar".to_string(), + + dynamic_linking: false, + executables: true, + // Today emcc emits two files - a .js file to bootstrap and + // possibly interpret the wasm, and a .wasm file + exe_suffix: ".js".to_string(), + linker_is_gnu: true, + allow_asm: false, + obj_is_bitcode: true, + max_atomic_width: Some(32), + post_link_args: vec!["-s".to_string(), "BINARYEN=1".to_string(), + "-s".to_string(), "ERROR_ON_UNDEFINED_SYMBOLS=1".to_string()], + .. Default::default() + }; + Ok(Target { + llvm_target: "asmjs-unknown-emscripten".to_string(), + target_endian: "little".to_string(), + target_pointer_width: "32".to_string(), + target_os: "emscripten".to_string(), + target_env: "".to_string(), + target_vendor: "unknown".to_string(), + data_layout: "e-p:32:32-i64:64-v128:32:128-n32-S128".to_string(), + arch: "wasm32".to_string(), + options: opts, + }) +} diff --git a/src/librustc_back/target/windows_base.rs b/src/librustc_back/target/windows_base.rs index c398ee40f2..19ca0df51b 100644 --- a/src/librustc_back/target/windows_base.rs +++ b/src/librustc_back/target/windows_base.rs @@ -26,7 +26,7 @@ pub fn opts() -> TargetOptions { no_default_libraries: true, is_like_windows: true, allows_weak_linkage: false, - pre_link_args: vec!( + pre_link_args: vec![ // And here, we see obscure linker flags #45. On windows, it has been // found to be necessary to have this flag to compile liblibc. // @@ -63,26 +63,26 @@ pub fn opts() -> TargetOptions { // Do not use the standard system startup files or libraries when linking "-nostdlib".to_string(), - ), - pre_link_objects_exe: vec!( + ], + pre_link_objects_exe: vec![ "crt2.o".to_string(), // mingw C runtime initialization for executables "rsbegin.o".to_string(), // Rust compiler runtime initialization, see rsbegin.rs - ), - pre_link_objects_dll: vec!( + ], + pre_link_objects_dll: vec![ "dllcrt2.o".to_string(), // mingw C runtime initialization for dlls "rsbegin.o".to_string(), - ), - late_link_args: vec!( + ], + late_link_args: vec![ "-lmingwex".to_string(), "-lmingw32".to_string(), "-lgcc".to_string(), // alas, mingw* libraries above depend on libgcc "-lmsvcrt".to_string(), "-luser32".to_string(), "-lkernel32".to_string(), - ), - post_link_objects: vec!( + ], + post_link_objects: vec![ "rsend.o".to_string() - ), + ], custom_unwind_resume: true, .. Default::default() diff --git a/src/librustc_back/target/x86_64_apple_darwin.rs b/src/librustc_back/target/x86_64_apple_darwin.rs index 65e4b1400f..b3c1561dbc 100644 --- a/src/librustc_back/target/x86_64_apple_darwin.rs +++ b/src/librustc_back/target/x86_64_apple_darwin.rs @@ -13,7 +13,7 @@ use target::{Target, TargetResult}; pub fn target() -> TargetResult { let mut base = super::apple_base::opts(); base.cpu = "core2".to_string(); - base.max_atomic_width = 128; // core2 support cmpxchg16b + base.max_atomic_width = Some(128); // core2 support cmpxchg16b base.eliminate_frame_pointer = false; base.pre_link_args.push("-m64".to_string()); diff --git a/src/librustc_back/target/x86_64_apple_ios.rs b/src/librustc_back/target/x86_64_apple_ios.rs index 3b8b636b6d..7a58bb34ce 100644 --- a/src/librustc_back/target/x86_64_apple_ios.rs +++ b/src/librustc_back/target/x86_64_apple_ios.rs @@ -23,7 +23,7 @@ pub fn target() -> TargetResult { target_env: "".to_string(), target_vendor: "apple".to_string(), options: TargetOptions { - max_atomic_width: 64, + max_atomic_width: Some(64), .. base } }) diff --git a/src/librustc_back/target/x86_64_pc_windows_gnu.rs b/src/librustc_back/target/x86_64_pc_windows_gnu.rs index 086e0e6bf4..321585cd65 100644 --- a/src/librustc_back/target/x86_64_pc_windows_gnu.rs +++ b/src/librustc_back/target/x86_64_pc_windows_gnu.rs @@ -14,7 +14,7 @@ pub fn target() -> TargetResult { let mut base = super::windows_base::opts(); base.cpu = "x86-64".to_string(); base.pre_link_args.push("-m64".to_string()); - base.max_atomic_width = 64; + base.max_atomic_width = Some(64); Ok(Target { llvm_target: "x86_64-pc-windows-gnu".to_string(), diff --git a/src/librustc_back/target/x86_64_pc_windows_msvc.rs b/src/librustc_back/target/x86_64_pc_windows_msvc.rs index 064f06e9b3..ea8909d213 100644 --- a/src/librustc_back/target/x86_64_pc_windows_msvc.rs +++ b/src/librustc_back/target/x86_64_pc_windows_msvc.rs @@ -13,7 +13,7 @@ use target::{Target, TargetResult}; pub fn target() -> TargetResult { let mut base = super::windows_msvc_base::opts(); base.cpu = "x86-64".to_string(); - base.max_atomic_width = 64; + base.max_atomic_width = Some(64); Ok(Target { llvm_target: "x86_64-pc-windows-msvc".to_string(), diff --git a/src/librustc_back/target/x86_64_rumprun_netbsd.rs b/src/librustc_back/target/x86_64_rumprun_netbsd.rs index fd6578c2a2..3313721439 100644 --- a/src/librustc_back/target/x86_64_rumprun_netbsd.rs +++ b/src/librustc_back/target/x86_64_rumprun_netbsd.rs @@ -16,7 +16,7 @@ pub fn target() -> TargetResult { base.pre_link_args.push("-m64".to_string()); base.linker = "x86_64-rumprun-netbsd-gcc".to_string(); base.ar = "x86_64-rumprun-netbsd-ar".to_string(); - base.max_atomic_width = 64; + base.max_atomic_width = Some(64); base.dynamic_linking = false; base.has_rpath = false; diff --git a/src/librustc_back/target/x86_64_sun_solaris.rs b/src/librustc_back/target/x86_64_sun_solaris.rs index 2a1feb937f..8e4fd94e7b 100644 --- a/src/librustc_back/target/x86_64_sun_solaris.rs +++ b/src/librustc_back/target/x86_64_sun_solaris.rs @@ -14,7 +14,7 @@ pub fn target() -> TargetResult { let mut base = super::solaris_base::opts(); base.pre_link_args.push("-m64".to_string()); base.cpu = "x86-64".to_string(); - base.max_atomic_width = 64; + base.max_atomic_width = Some(64); Ok(Target { llvm_target: "x86_64-pc-solaris".to_string(), diff --git a/src/librustc_back/target/x86_64_unknown_bitrig.rs b/src/librustc_back/target/x86_64_unknown_bitrig.rs index 3820965589..eda16c2946 100644 --- a/src/librustc_back/target/x86_64_unknown_bitrig.rs +++ b/src/librustc_back/target/x86_64_unknown_bitrig.rs @@ -13,7 +13,7 @@ use target::{Target, TargetResult}; pub fn target() -> TargetResult { let mut base = super::bitrig_base::opts(); base.cpu = "x86-64".to_string(); - base.max_atomic_width = 64; + base.max_atomic_width = Some(64); base.pre_link_args.push("-m64".to_string()); Ok(Target { diff --git a/src/librustc_back/target/x86_64_unknown_dragonfly.rs b/src/librustc_back/target/x86_64_unknown_dragonfly.rs index 7e40d49b87..194efb8fc2 100644 --- a/src/librustc_back/target/x86_64_unknown_dragonfly.rs +++ b/src/librustc_back/target/x86_64_unknown_dragonfly.rs @@ -13,7 +13,7 @@ use target::{Target, TargetResult}; pub fn target() -> TargetResult { let mut base = super::dragonfly_base::opts(); base.cpu = "x86-64".to_string(); - base.max_atomic_width = 64; + base.max_atomic_width = Some(64); base.pre_link_args.push("-m64".to_string()); Ok(Target { diff --git a/src/librustc_back/target/x86_64_unknown_freebsd.rs b/src/librustc_back/target/x86_64_unknown_freebsd.rs index f38cdd4bec..b127bee163 100644 --- a/src/librustc_back/target/x86_64_unknown_freebsd.rs +++ b/src/librustc_back/target/x86_64_unknown_freebsd.rs @@ -13,7 +13,7 @@ use target::{Target, TargetResult}; pub fn target() -> TargetResult { let mut base = super::freebsd_base::opts(); base.cpu = "x86-64".to_string(); - base.max_atomic_width = 64; + base.max_atomic_width = Some(64); base.pre_link_args.push("-m64".to_string()); Ok(Target { diff --git a/src/librustc_back/target/x86_64_unknown_fuchsia.rs b/src/librustc_back/target/x86_64_unknown_fuchsia.rs new file mode 100644 index 0000000000..08fe17a556 --- /dev/null +++ b/src/librustc_back/target/x86_64_unknown_fuchsia.rs @@ -0,0 +1,30 @@ +// Copyright 2016 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +use target::{Target, TargetResult}; + +pub fn target() -> TargetResult { + let mut base = super::fuchsia_base::opts(); + base.cpu = "x86-64".to_string(); + base.max_atomic_width = Some(64); + base.pre_link_args.push("-m64".to_string()); + + Ok(Target { + llvm_target: "x86_64-unknown-fuchsia".to_string(), + target_endian: "little".to_string(), + target_pointer_width: "64".to_string(), + data_layout: "e-m:e-i64:64-f80:128-n8:16:32:64-S128".to_string(), + arch: "x86_64".to_string(), + target_os: "fuchsia".to_string(), + target_env: "".to_string(), + target_vendor: "unknown".to_string(), + options: base, + }) +} diff --git a/src/librustc_back/target/x86_64_unknown_haiku.rs b/src/librustc_back/target/x86_64_unknown_haiku.rs index 171e88cee5..7cf0599037 100644 --- a/src/librustc_back/target/x86_64_unknown_haiku.rs +++ b/src/librustc_back/target/x86_64_unknown_haiku.rs @@ -13,7 +13,7 @@ use target::{Target, TargetResult}; pub fn target() -> TargetResult { let mut base = super::haiku_base::opts(); base.cpu = "x86-64".to_string(); - base.max_atomic_width = 64; + base.max_atomic_width = Some(64); base.pre_link_args.push("-m64".to_string()); Ok(Target { diff --git a/src/librustc_back/target/x86_64_unknown_linux_gnu.rs b/src/librustc_back/target/x86_64_unknown_linux_gnu.rs index ef81d397a8..f95bcb556e 100644 --- a/src/librustc_back/target/x86_64_unknown_linux_gnu.rs +++ b/src/librustc_back/target/x86_64_unknown_linux_gnu.rs @@ -13,7 +13,7 @@ use target::{Target, TargetResult}; pub fn target() -> TargetResult { let mut base = super::linux_base::opts(); base.cpu = "x86-64".to_string(); - base.max_atomic_width = 64; + base.max_atomic_width = Some(64); base.pre_link_args.push("-m64".to_string()); Ok(Target { diff --git a/src/librustc_back/target/x86_64_unknown_linux_musl.rs b/src/librustc_back/target/x86_64_unknown_linux_musl.rs index 4bad7754b3..c3bf9dcca6 100644 --- a/src/librustc_back/target/x86_64_unknown_linux_musl.rs +++ b/src/librustc_back/target/x86_64_unknown_linux_musl.rs @@ -13,7 +13,7 @@ use target::{Target, TargetResult}; pub fn target() -> TargetResult { let mut base = super::linux_musl_base::opts(); base.cpu = "x86-64".to_string(); - base.max_atomic_width = 64; + base.max_atomic_width = Some(64); base.pre_link_args.push("-m64".to_string()); Ok(Target { diff --git a/src/librustc_back/target/x86_64_unknown_netbsd.rs b/src/librustc_back/target/x86_64_unknown_netbsd.rs index 2d0b1e2a93..87a7c18464 100644 --- a/src/librustc_back/target/x86_64_unknown_netbsd.rs +++ b/src/librustc_back/target/x86_64_unknown_netbsd.rs @@ -13,7 +13,7 @@ use target::{Target, TargetResult}; pub fn target() -> TargetResult { let mut base = super::netbsd_base::opts(); base.cpu = "x86-64".to_string(); - base.max_atomic_width = 64; + base.max_atomic_width = Some(64); base.pre_link_args.push("-m64".to_string()); Ok(Target { diff --git a/src/librustc_back/target/x86_64_unknown_openbsd.rs b/src/librustc_back/target/x86_64_unknown_openbsd.rs index 339dbd591a..e9d645b0d3 100644 --- a/src/librustc_back/target/x86_64_unknown_openbsd.rs +++ b/src/librustc_back/target/x86_64_unknown_openbsd.rs @@ -13,7 +13,7 @@ use target::{Target, TargetResult}; pub fn target() -> TargetResult { let mut base = super::openbsd_base::opts(); base.cpu = "x86-64".to_string(); - base.max_atomic_width = 64; + base.max_atomic_width = Some(64); base.pre_link_args.push("-m64".to_string()); Ok(Target { diff --git a/src/librustc_borrowck/borrowck/check_loans.rs b/src/librustc_borrowck/borrowck/check_loans.rs index 089733da53..b2032e6a1b 100644 --- a/src/librustc_borrowck/borrowck/check_loans.rs +++ b/src/librustc_borrowck/borrowck/check_loans.rs @@ -135,15 +135,12 @@ impl<'a, 'tcx> euv::Delegate<'tcx> for CheckLoanCtxt<'a, 'tcx> { borrow_id, cmt, loan_region, bk, loan_cause); - match opt_loan_path(&cmt) { - Some(lp) => { - let moved_value_use_kind = match loan_cause { - euv::ClosureCapture(_) => MovedInCapture, - _ => MovedInUse, - }; - self.check_if_path_is_moved(borrow_id, borrow_span, moved_value_use_kind, &lp); - } - None => { } + if let Some(lp) = opt_loan_path(&cmt) { + let moved_value_use_kind = match loan_cause { + euv::ClosureCapture(_) => MovedInCapture, + _ => MovedInUse, + }; + self.check_if_path_is_moved(borrow_id, borrow_span, moved_value_use_kind, &lp); } self.check_for_conflicting_loans(borrow_id); @@ -158,33 +155,29 @@ impl<'a, 'tcx> euv::Delegate<'tcx> for CheckLoanCtxt<'a, 'tcx> { debug!("mutate(assignment_id={}, assignee_cmt={:?})", assignment_id, assignee_cmt); - match opt_loan_path(&assignee_cmt) { - Some(lp) => { - match mode { - MutateMode::Init | MutateMode::JustWrite => { - // In a case like `path = 1`, then path does not - // have to be *FULLY* initialized, but we still - // must be careful lest it contains derefs of - // pointers. - self.check_if_assigned_path_is_moved(assignee_cmt.id, - assignment_span, - MovedInUse, - &lp); - } - MutateMode::WriteAndRead => { - // In a case like `path += 1`, then path must be - // fully initialized, since we will read it before - // we write it. - self.check_if_path_is_moved(assignee_cmt.id, - assignment_span, - MovedInUse, - &lp); - } + if let Some(lp) = opt_loan_path(&assignee_cmt) { + match mode { + MutateMode::Init | MutateMode::JustWrite => { + // In a case like `path = 1`, then path does not + // have to be *FULLY* initialized, but we still + // must be careful lest it contains derefs of + // pointers. + self.check_if_assigned_path_is_moved(assignee_cmt.id, + assignment_span, + MovedInUse, + &lp); + } + MutateMode::WriteAndRead => { + // In a case like `path += 1`, then path must be + // fully initialized, since we will read it before + // we write it. + self.check_if_path_is_moved(assignee_cmt.id, + assignment_span, + MovedInUse, + &lp); } } - None => { } } - self.check_assignment(assignment_id, assignment_span, assignee_cmt); } @@ -601,39 +594,36 @@ impl<'a, 'tcx> CheckLoanCtxt<'a, 'tcx> { span: Span, cmt: mc::cmt<'tcx>, mode: euv::ConsumeMode) { - match opt_loan_path(&cmt) { - Some(lp) => { - let moved_value_use_kind = match mode { - euv::Copy => { - self.check_for_copy_of_frozen_path(id, span, &lp); - MovedInUse - } - euv::Move(_) => { - match self.move_data.kind_of_move_of_path(id, &lp) { - None => { - // Sometimes moves don't have a move kind; - // this either means that the original move - // was from something illegal to move, - // or was moved from referent of an unsafe - // pointer or something like that. + if let Some(lp) = opt_loan_path(&cmt) { + let moved_value_use_kind = match mode { + euv::Copy => { + self.check_for_copy_of_frozen_path(id, span, &lp); + MovedInUse + } + euv::Move(_) => { + match self.move_data.kind_of_move_of_path(id, &lp) { + None => { + // Sometimes moves don't have a move kind; + // this either means that the original move + // was from something illegal to move, + // or was moved from referent of an unsafe + // pointer or something like that. + MovedInUse + } + Some(move_kind) => { + self.check_for_move_of_borrowed_path(id, span, + &lp, move_kind); + if move_kind == move_data::Captured { + MovedInCapture + } else { MovedInUse } - Some(move_kind) => { - self.check_for_move_of_borrowed_path(id, span, - &lp, move_kind); - if move_kind == move_data::Captured { - MovedInCapture - } else { - MovedInUse - } - } } } - }; + } + }; - self.check_if_path_is_moved(id, span, moved_value_use_kind, &lp); - } - None => { } + self.check_if_path_is_moved(id, span, moved_value_use_kind, &lp); } } diff --git a/src/librustc_borrowck/borrowck/gather_loans/gather_moves.rs b/src/librustc_borrowck/borrowck/gather_loans/gather_moves.rs index 9bdc6887f6..51574868f9 100644 --- a/src/librustc_borrowck/borrowck/gather_loans/gather_moves.rs +++ b/src/librustc_borrowck/borrowck/gather_loans/gather_moves.rs @@ -37,7 +37,7 @@ pub fn gather_decl<'a, 'tcx>(bccx: &BorrowckCtxt<'a, 'tcx>, decl_id: ast::NodeId, _decl_span: Span, var_id: ast::NodeId) { - let ty = bccx.tcx.node_id_to_type(var_id); + let ty = bccx.tcx.tables().node_id_to_type(var_id); let loan_path = Rc::new(LoanPath::new(LpVar(var_id), ty)); move_data.add_move(bccx.tcx, loan_path, decl_id, Declared); } diff --git a/src/librustc_borrowck/borrowck/gather_loans/move_error.rs b/src/librustc_borrowck/borrowck/gather_loans/move_error.rs index 9fbf1492f5..47f8d97870 100644 --- a/src/librustc_borrowck/borrowck/gather_loans/move_error.rs +++ b/src/librustc_borrowck/borrowck/gather_loans/move_error.rs @@ -92,7 +92,7 @@ fn group_errors_with_same_origin<'tcx>(errors: &Vec>) let move_from_id = error.move_from.id; debug!("append_to_grouped_errors(move_from_id={})", move_from_id); let move_to = if error.move_to.is_some() { - vec!(error.move_to.clone().unwrap()) + vec![error.move_to.clone().unwrap()] } else { Vec::new() }; diff --git a/src/librustc_borrowck/borrowck/mir/abs_domain.rs b/src/librustc_borrowck/borrowck/mir/abs_domain.rs index 155b615d83..5e61c2ec7a 100644 --- a/src/librustc_borrowck/borrowck/mir/abs_domain.rs +++ b/src/librustc_borrowck/borrowck/mir/abs_domain.rs @@ -21,13 +21,11 @@ //! `a[x]` would still overlap them both. But that is not this //! representation does today.) -use rustc::mir::repr::{Lvalue, LvalueElem}; -use rustc::mir::repr::{Operand, Projection, ProjectionElem}; +use rustc::mir::LvalueElem; +use rustc::mir::{Operand, ProjectionElem}; #[derive(Copy, Clone, PartialEq, Eq, Hash, Debug)] pub struct AbstractOperand; -pub type AbstractProjection<'tcx> = - Projection<'tcx, Lvalue<'tcx>, AbstractOperand>; pub type AbstractElem<'tcx> = ProjectionElem<'tcx, AbstractOperand>; diff --git a/src/librustc_borrowck/borrowck/mir/dataflow/graphviz.rs b/src/librustc_borrowck/borrowck/mir/dataflow/graphviz.rs index 91be50d11f..28f5872386 100644 --- a/src/librustc_borrowck/borrowck/mir/dataflow/graphviz.rs +++ b/src/librustc_borrowck/borrowck/mir/dataflow/graphviz.rs @@ -11,7 +11,9 @@ //! Hook into libgraphviz for rendering dataflow graphs for MIR. use syntax::ast::NodeId; -use rustc::mir::repr::{BasicBlock, Mir}; +use rustc::mir::{BasicBlock, Mir}; +use rustc_data_structures::bitslice::bits_to_string; +use rustc_data_structures::indexed_set::{IdxSet}; use rustc_data_structures::indexed_vec::Idx; use dot; @@ -27,8 +29,6 @@ use std::path::Path; use super::super::MoveDataParamEnv; use super::super::MirBorrowckCtxtPreDataflow; -use bitslice::bits_to_string; -use indexed_set::{IdxSet}; use super::{BitDenotation, DataflowState}; impl DataflowState { diff --git a/src/librustc_borrowck/borrowck/mir/dataflow/impls.rs b/src/librustc_borrowck/borrowck/mir/dataflow/impls.rs index 55dda8eda3..fcb453d81a 100644 --- a/src/librustc_borrowck/borrowck/mir/dataflow/impls.rs +++ b/src/librustc_borrowck/borrowck/mir/dataflow/impls.rs @@ -9,7 +9,10 @@ // except according to those terms. use rustc::ty::TyCtxt; -use rustc::mir::repr::{self, Mir, Location}; +use rustc::mir::{self, Mir, Location}; +use rustc_data_structures::bitslice::BitSlice; // adds set_bit/get_bit to &[usize] bitvector rep. +use rustc_data_structures::bitslice::{BitwiseOperator}; +use rustc_data_structures::indexed_set::{IdxSet}; use rustc_data_structures::indexed_vec::Idx; use super::super::gather_moves::{MoveOutIndex, MovePathIndex}; @@ -21,10 +24,6 @@ use super::super::on_lookup_result_bits; use super::{BitDenotation, BlockSets, DataflowOperator}; -use bitslice::BitSlice; // adds set_bit/get_bit to &[usize] bitvector rep. -use bitslice::{BitwiseOperator}; -use indexed_set::{IdxSet}; - // Dataflow analyses are built upon some interpretation of the // bitvectors attached to each basic block, represented via a // zero-sized structure. @@ -246,7 +245,7 @@ impl<'a, 'tcx> BitDenotation for MaybeInitializedLvals<'a, 'tcx> { fn statement_effect(&self, ctxt: &Self::Ctxt, sets: &mut BlockSets, - bb: repr::BasicBlock, + bb: mir::BasicBlock, idx: usize) { drop_flag_effects_for_location( @@ -259,7 +258,7 @@ impl<'a, 'tcx> BitDenotation for MaybeInitializedLvals<'a, 'tcx> { fn terminator_effect(&self, ctxt: &Self::Ctxt, sets: &mut BlockSets, - bb: repr::BasicBlock, + bb: mir::BasicBlock, statements_len: usize) { drop_flag_effects_for_location( @@ -272,9 +271,9 @@ impl<'a, 'tcx> BitDenotation for MaybeInitializedLvals<'a, 'tcx> { fn propagate_call_return(&self, ctxt: &Self::Ctxt, in_out: &mut IdxSet, - _call_bb: repr::BasicBlock, - _dest_bb: repr::BasicBlock, - dest_lval: &repr::Lvalue) { + _call_bb: mir::BasicBlock, + _dest_bb: mir::BasicBlock, + dest_lval: &mir::Lvalue) { // when a call returns successfully, that means we need to set // the bits for that dest_lval to 1 (initialized). on_lookup_result_bits(self.tcx, self.mir, &ctxt.move_data, @@ -307,7 +306,7 @@ impl<'a, 'tcx> BitDenotation for MaybeUninitializedLvals<'a, 'tcx> { fn statement_effect(&self, ctxt: &Self::Ctxt, sets: &mut BlockSets, - bb: repr::BasicBlock, + bb: mir::BasicBlock, idx: usize) { drop_flag_effects_for_location( @@ -320,7 +319,7 @@ impl<'a, 'tcx> BitDenotation for MaybeUninitializedLvals<'a, 'tcx> { fn terminator_effect(&self, ctxt: &Self::Ctxt, sets: &mut BlockSets, - bb: repr::BasicBlock, + bb: mir::BasicBlock, statements_len: usize) { drop_flag_effects_for_location( @@ -333,9 +332,9 @@ impl<'a, 'tcx> BitDenotation for MaybeUninitializedLvals<'a, 'tcx> { fn propagate_call_return(&self, ctxt: &Self::Ctxt, in_out: &mut IdxSet, - _call_bb: repr::BasicBlock, - _dest_bb: repr::BasicBlock, - dest_lval: &repr::Lvalue) { + _call_bb: mir::BasicBlock, + _dest_bb: mir::BasicBlock, + dest_lval: &mir::Lvalue) { // when a call returns successfully, that means we need to set // the bits for that dest_lval to 0 (initialized). on_lookup_result_bits(self.tcx, self.mir, &ctxt.move_data, @@ -367,7 +366,7 @@ impl<'a, 'tcx> BitDenotation for DefinitelyInitializedLvals<'a, 'tcx> { fn statement_effect(&self, ctxt: &Self::Ctxt, sets: &mut BlockSets, - bb: repr::BasicBlock, + bb: mir::BasicBlock, idx: usize) { drop_flag_effects_for_location( @@ -380,7 +379,7 @@ impl<'a, 'tcx> BitDenotation for DefinitelyInitializedLvals<'a, 'tcx> { fn terminator_effect(&self, ctxt: &Self::Ctxt, sets: &mut BlockSets, - bb: repr::BasicBlock, + bb: mir::BasicBlock, statements_len: usize) { drop_flag_effects_for_location( @@ -393,9 +392,9 @@ impl<'a, 'tcx> BitDenotation for DefinitelyInitializedLvals<'a, 'tcx> { fn propagate_call_return(&self, ctxt: &Self::Ctxt, in_out: &mut IdxSet, - _call_bb: repr::BasicBlock, - _dest_bb: repr::BasicBlock, - dest_lval: &repr::Lvalue) { + _call_bb: mir::BasicBlock, + _dest_bb: mir::BasicBlock, + dest_lval: &mir::Lvalue) { // when a call returns successfully, that means we need to set // the bits for that dest_lval to 1 (initialized). on_lookup_result_bits(self.tcx, self.mir, &ctxt.move_data, @@ -419,7 +418,7 @@ impl<'a, 'tcx> BitDenotation for MovingOutStatements<'a, 'tcx> { fn statement_effect(&self, ctxt: &Self::Ctxt, sets: &mut BlockSets, - bb: repr::BasicBlock, + bb: mir::BasicBlock, idx: usize) { let (tcx, mir, move_data) = (self.tcx, self.mir, &ctxt.move_data); let stmt = &mir[bb].statements[idx]; @@ -438,10 +437,10 @@ impl<'a, 'tcx> BitDenotation for MovingOutStatements<'a, 'tcx> { } let bits_per_block = self.bits_per_block(ctxt); match stmt.kind { - repr::StatementKind::SetDiscriminant { .. } => { + mir::StatementKind::SetDiscriminant { .. } => { span_bug!(stmt.source_info.span, "SetDiscriminant should not exist in borrowck"); } - repr::StatementKind::Assign(ref lvalue, _) => { + mir::StatementKind::Assign(ref lvalue, _) => { // assigning into this `lvalue` kills all // MoveOuts from it, and *also* all MoveOuts // for children and associated fragment sets. @@ -454,16 +453,16 @@ impl<'a, 'tcx> BitDenotation for MovingOutStatements<'a, 'tcx> { sets.kill_set.add(&moi); }); } - repr::StatementKind::StorageLive(_) | - repr::StatementKind::StorageDead(_) | - repr::StatementKind::Nop => {} + mir::StatementKind::StorageLive(_) | + mir::StatementKind::StorageDead(_) | + mir::StatementKind::Nop => {} } } fn terminator_effect(&self, ctxt: &Self::Ctxt, sets: &mut BlockSets, - bb: repr::BasicBlock, + bb: mir::BasicBlock, statements_len: usize) { let (mir, move_data) = (self.mir, &ctxt.move_data); @@ -482,9 +481,9 @@ impl<'a, 'tcx> BitDenotation for MovingOutStatements<'a, 'tcx> { fn propagate_call_return(&self, ctxt: &Self::Ctxt, in_out: &mut IdxSet, - _call_bb: repr::BasicBlock, - _dest_bb: repr::BasicBlock, - dest_lval: &repr::Lvalue) { + _call_bb: mir::BasicBlock, + _dest_bb: mir::BasicBlock, + dest_lval: &mir::Lvalue) { let move_data = &ctxt.move_data; let bits_per_block = self.bits_per_block(ctxt); diff --git a/src/librustc_borrowck/borrowck/mir/dataflow/mod.rs b/src/librustc_borrowck/borrowck/mir/dataflow/mod.rs index a9b4de4509..51817afbfe 100644 --- a/src/librustc_borrowck/borrowck/mir/dataflow/mod.rs +++ b/src/librustc_borrowck/borrowck/mir/dataflow/mod.rs @@ -8,10 +8,12 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. +use rustc_data_structures::indexed_set::{IdxSet, IdxSetBuf}; use rustc_data_structures::indexed_vec::Idx; +use rustc_data_structures::bitslice::{bitwise, BitwiseOperator}; use rustc::ty::TyCtxt; -use rustc::mir::repr::{self, Mir}; +use rustc::mir::{self, Mir}; use std::fmt::Debug; use std::io; @@ -22,9 +24,6 @@ use std::usize; use super::MirBorrowckCtxtPreDataflow; use super::MoveDataParamEnv; -use bitslice::{bitwise, BitwiseOperator}; -use indexed_set::{IdxSet, IdxSetBuf}; - pub use self::sanity_check::sanity_check_via_rustc_peek; pub use self::impls::{MaybeInitializedLvals, MaybeUninitializedLvals}; pub use self::impls::{DefinitelyInitializedLvals, MovingOutStatements}; @@ -79,14 +78,12 @@ impl<'a, 'tcx: 'a, BD> DataflowAnalysis<'a, 'tcx, BD> // the kill-sets. { - let sets = &mut self.flow_state.sets.for_block(repr::START_BLOCK.index()); + let sets = &mut self.flow_state.sets.for_block(mir::START_BLOCK.index()); self.flow_state.operator.start_block_effect(&self.ctxt, sets); } for (bb, data) in self.mir.basic_blocks().iter_enumerated() { - let &repr::BasicBlockData { ref statements, - ref terminator, - is_cleanup: _ } = data; + let &mir::BasicBlockData { ref statements, ref terminator, is_cleanup: _ } = data; let sets = &mut self.flow_state.sets.for_block(bb.index()); for j_stmt in 0..statements.len() { @@ -123,7 +120,7 @@ impl<'b, 'a: 'b, 'tcx: 'a, BD> PropagationContext<'b, 'a, 'tcx, BD> in_out.subtract(sets.kill_set); } builder.propagate_bits_into_graph_successors_of( - in_out, &mut self.changed, (repr::BasicBlock::new(bb_idx), bb_data)); + in_out, &mut self.changed, (mir::BasicBlock::new(bb_idx), bb_data)); } } } @@ -337,7 +334,7 @@ pub trait BitDenotation { fn statement_effect(&self, ctxt: &Self::Ctxt, sets: &mut BlockSets, - bb: repr::BasicBlock, + bb: mir::BasicBlock, idx_stmt: usize); /// Mutates the block-sets (the flow sets for the given @@ -353,7 +350,7 @@ pub trait BitDenotation { fn terminator_effect(&self, ctxt: &Self::Ctxt, sets: &mut BlockSets, - bb: repr::BasicBlock, + bb: mir::BasicBlock, idx_term: usize); /// Mutates the block-sets according to the (flow-dependent) @@ -378,9 +375,9 @@ pub trait BitDenotation { fn propagate_call_return(&self, ctxt: &Self::Ctxt, in_out: &mut IdxSet, - call_bb: repr::BasicBlock, - dest_bb: repr::BasicBlock, - dest_lval: &repr::Lvalue); + call_bb: mir::BasicBlock, + dest_bb: mir::BasicBlock, + dest_lval: &mir::Lvalue); } impl<'a, 'tcx: 'a, D> DataflowAnalysis<'a, 'tcx, D> @@ -445,39 +442,39 @@ impl<'a, 'tcx: 'a, D> DataflowAnalysis<'a, 'tcx, D> &mut self, in_out: &mut IdxSet, changed: &mut bool, - (bb, bb_data): (repr::BasicBlock, &repr::BasicBlockData)) + (bb, bb_data): (mir::BasicBlock, &mir::BasicBlockData)) { match bb_data.terminator().kind { - repr::TerminatorKind::Return | - repr::TerminatorKind::Resume | - repr::TerminatorKind::Unreachable => {} - repr::TerminatorKind::Goto { ref target } | - repr::TerminatorKind::Assert { ref target, cleanup: None, .. } | - repr::TerminatorKind::Drop { ref target, location: _, unwind: None } | - repr::TerminatorKind::DropAndReplace { + mir::TerminatorKind::Return | + mir::TerminatorKind::Resume | + mir::TerminatorKind::Unreachable => {} + mir::TerminatorKind::Goto { ref target } | + mir::TerminatorKind::Assert { ref target, cleanup: None, .. } | + mir::TerminatorKind::Drop { ref target, location: _, unwind: None } | + mir::TerminatorKind::DropAndReplace { ref target, value: _, location: _, unwind: None } => { self.propagate_bits_into_entry_set_for(in_out, changed, target); } - repr::TerminatorKind::Assert { ref target, cleanup: Some(ref unwind), .. } | - repr::TerminatorKind::Drop { ref target, location: _, unwind: Some(ref unwind) } | - repr::TerminatorKind::DropAndReplace { + mir::TerminatorKind::Assert { ref target, cleanup: Some(ref unwind), .. } | + mir::TerminatorKind::Drop { ref target, location: _, unwind: Some(ref unwind) } | + mir::TerminatorKind::DropAndReplace { ref target, value: _, location: _, unwind: Some(ref unwind) } => { self.propagate_bits_into_entry_set_for(in_out, changed, target); self.propagate_bits_into_entry_set_for(in_out, changed, unwind); } - repr::TerminatorKind::If { ref targets, .. } => { + mir::TerminatorKind::If { ref targets, .. } => { self.propagate_bits_into_entry_set_for(in_out, changed, &targets.0); self.propagate_bits_into_entry_set_for(in_out, changed, &targets.1); } - repr::TerminatorKind::Switch { ref targets, .. } | - repr::TerminatorKind::SwitchInt { ref targets, .. } => { + mir::TerminatorKind::Switch { ref targets, .. } | + mir::TerminatorKind::SwitchInt { ref targets, .. } => { for target in targets { self.propagate_bits_into_entry_set_for(in_out, changed, target); } } - repr::TerminatorKind::Call { ref cleanup, ref destination, func: _, args: _ } => { + mir::TerminatorKind::Call { ref cleanup, ref destination, func: _, args: _ } => { if let Some(ref unwind) = *cleanup { self.propagate_bits_into_entry_set_for(in_out, changed, unwind); } @@ -495,7 +492,7 @@ impl<'a, 'tcx: 'a, D> DataflowAnalysis<'a, 'tcx, D> fn propagate_bits_into_entry_set_for(&mut self, in_out: &IdxSet, changed: &mut bool, - bb: &repr::BasicBlock) { + bb: &mir::BasicBlock) { let entry_set = self.flow_state.sets.for_block(bb.index()).on_entry; let set_changed = bitwise(entry_set.words_mut(), in_out.words(), diff --git a/src/librustc_borrowck/borrowck/mir/dataflow/sanity_check.rs b/src/librustc_borrowck/borrowck/mir/dataflow/sanity_check.rs index aeb91f06a9..b8c26a0512 100644 --- a/src/librustc_borrowck/borrowck/mir/dataflow/sanity_check.rs +++ b/src/librustc_borrowck/borrowck/mir/dataflow/sanity_check.rs @@ -13,7 +13,7 @@ use syntax::ast; use syntax_pos::Span; use rustc::ty::{self, TyCtxt}; -use rustc::mir::repr::{self, Mir}; +use rustc::mir::{self, Mir}; use rustc_data_structures::indexed_vec::Idx; use super::super::gather_moves::{MovePathIndex, LookupResult}; @@ -59,13 +59,11 @@ fn each_block<'a, 'tcx, O>(tcx: TyCtxt<'a, 'tcx, 'tcx>, mir: &Mir<'tcx>, ctxt: &O::Ctxt, results: &DataflowResults, - bb: repr::BasicBlock) where + bb: mir::BasicBlock) where O: BitDenotation, Idx=MovePathIndex> { let move_data = &ctxt.move_data; - let repr::BasicBlockData { ref statements, - ref terminator, - is_cleanup: _ } = mir[bb]; + let mir::BasicBlockData { ref statements, ref terminator, is_cleanup: _ } = mir[bb]; let (args, span) = match is_rustc_peek(tcx, terminator) { Some(args_and_span) => args_and_span, @@ -73,11 +71,13 @@ fn each_block<'a, 'tcx, O>(tcx: TyCtxt<'a, 'tcx, 'tcx>, }; assert!(args.len() == 1); let peek_arg_lval = match args[0] { - repr::Operand::Consume(ref lval @ repr::Lvalue::Temp(_)) => { - lval - } - repr::Operand::Consume(_) | - repr::Operand::Constant(_) => { + mir::Operand::Consume(ref lval @ mir::Lvalue::Local(_)) => Some(lval), + _ => None, + }; + + let peek_arg_lval = match peek_arg_lval { + Some(arg) => arg, + None => { tcx.sess.diagnostic().span_err( span, "dataflow::sanity_check cannot feed a non-temp to rustc_peek."); return; @@ -101,21 +101,19 @@ fn each_block<'a, 'tcx, O>(tcx: TyCtxt<'a, 'tcx, 'tcx>, for (j, stmt) in statements.iter().enumerate() { debug!("rustc_peek: ({:?},{}) {:?}", bb, j, stmt); let (lvalue, rvalue) = match stmt.kind { - repr::StatementKind::Assign(ref lvalue, ref rvalue) => { + mir::StatementKind::Assign(ref lvalue, ref rvalue) => { (lvalue, rvalue) } - repr::StatementKind::StorageLive(_) | - repr::StatementKind::StorageDead(_) | - repr::StatementKind::Nop => continue, - repr::StatementKind::SetDiscriminant{ .. } => + mir::StatementKind::StorageLive(_) | + mir::StatementKind::StorageDead(_) | + mir::StatementKind::Nop => continue, + mir::StatementKind::SetDiscriminant{ .. } => span_bug!(stmt.source_info.span, "sanity_check should run before Deaggregator inserts SetDiscriminant"), }; if lvalue == peek_arg_lval { - if let repr::Rvalue::Ref(_, - repr::BorrowKind::Shared, - ref peeking_at_lval) = *rvalue { + if let mir::Rvalue::Ref(_, mir::BorrowKind::Shared, ref peeking_at_lval) = *rvalue { // Okay, our search is over. match move_data.rev_lookup.find(peeking_at_lval) { LookupResult::Exact(peek_mpi) => { @@ -160,12 +158,12 @@ fn each_block<'a, 'tcx, O>(tcx: TyCtxt<'a, 'tcx, 'tcx>, } fn is_rustc_peek<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, - terminator: &'a Option>) - -> Option<(&'a [repr::Operand<'tcx>], Span)> { - if let Some(repr::Terminator { ref kind, source_info, .. }) = *terminator { - if let repr::TerminatorKind::Call { func: ref oper, ref args, .. } = *kind + terminator: &'a Option>) + -> Option<(&'a [mir::Operand<'tcx>], Span)> { + if let Some(mir::Terminator { ref kind, source_info, .. }) = *terminator { + if let mir::TerminatorKind::Call { func: ref oper, ref args, .. } = *kind { - if let repr::Operand::Constant(ref func) = *oper + if let mir::Operand::Constant(ref func) = *oper { if let ty::TyFnDef(def_id, _, &ty::BareFnTy { abi, .. }) = func.ty.sty { diff --git a/src/librustc_borrowck/borrowck/mir/elaborate_drops.rs b/src/librustc_borrowck/borrowck/mir/elaborate_drops.rs index 96702b209a..191cd981b6 100644 --- a/src/librustc_borrowck/borrowck/mir/elaborate_drops.rs +++ b/src/librustc_borrowck/borrowck/mir/elaborate_drops.rs @@ -8,7 +8,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -use indexed_set::IdxSetBuf; use super::gather_moves::{MoveData, MovePathIndex, LookupResult}; use super::dataflow::{MaybeInitializedLvals, MaybeUninitializedLvals}; use super::dataflow::{DataflowResults}; @@ -18,11 +17,12 @@ use super::{DropFlagState, MoveDataParamEnv}; use super::patch::MirPatch; use rustc::ty::{self, Ty, TyCtxt}; use rustc::ty::subst::{Kind, Subst, Substs}; -use rustc::mir::repr::*; +use rustc::mir::*; use rustc::mir::transform::{Pass, MirPass, MirSource}; use rustc::middle::const_val::ConstVal; use rustc::middle::lang_items; use rustc::util::nodemap::FnvHashMap; +use rustc_data_structures::indexed_set::IdxSetBuf; use rustc_data_structures::indexed_vec::Idx; use syntax_pos::Span; @@ -118,7 +118,7 @@ struct ElaborateDropsCtxt<'a, 'tcx: 'a> { env: &'a MoveDataParamEnv<'tcx>, flow_inits: DataflowResults>, flow_uninits: DataflowResults>, - drop_flags: FnvHashMap, + drop_flags: FnvHashMap, patch: MirPatch<'tcx>, } @@ -164,7 +164,7 @@ impl<'b, 'tcx> ElaborateDropsCtxt<'b, 'tcx> { } fn drop_flag(&mut self, index: MovePathIndex) -> Option> { - self.drop_flags.get(&index).map(|t| Lvalue::Temp(*t)) + self.drop_flags.get(&index).map(|t| Lvalue::Local(*t)) } /// create a patch that elaborates all drops in the input @@ -847,17 +847,17 @@ impl<'b, 'tcx> ElaborateDropsCtxt<'b, 'tcx> { statements.push(Statement { source_info: c.source_info, kind: StatementKind::Assign( - Lvalue::Temp(flag), + Lvalue::Local(flag), self.constant_bool(c.source_info.span, false) ) }); } let tcx = self.tcx; - let unit_temp = Lvalue::Temp(self.patch.new_temp(tcx.mk_nil())); + let unit_temp = Lvalue::Local(self.patch.new_temp(tcx.mk_nil())); let free_func = tcx.lang_items.require(lang_items::BoxFreeFnLangItem) .unwrap_or_else(|e| tcx.sess.fatal(&e)); - let substs = Substs::new(tcx, iter::once(Kind::from(ty))); + let substs = tcx.mk_substs(iter::once(Kind::from(ty))); let fty = tcx.lookup_item_type(free_func).ty.subst(tcx, substs); self.patch.new_block(BasicBlockData { @@ -917,7 +917,7 @@ impl<'b, 'tcx> ElaborateDropsCtxt<'b, 'tcx> { if let Some(&flag) = self.drop_flags.get(&path) { let span = self.patch.source_info_for_location(self.mir, loc).span; let val = self.constant_bool(span, val.value()); - self.patch.add_assign(loc, Lvalue::Temp(flag), val); + self.patch.add_assign(loc, Lvalue::Local(flag), val); } } @@ -926,7 +926,7 @@ impl<'b, 'tcx> ElaborateDropsCtxt<'b, 'tcx> { let span = self.patch.source_info_for_location(self.mir, loc).span; let false_ = self.constant_bool(span, false); for flag in self.drop_flags.values() { - self.patch.add_assign(loc, Lvalue::Temp(*flag), false_.clone()); + self.patch.add_assign(loc, Lvalue::Local(*flag), false_.clone()); } } diff --git a/src/librustc_borrowck/borrowck/mir/gather_moves.rs b/src/librustc_borrowck/borrowck/mir/gather_moves.rs index 6346c1e588..1dc5769e63 100644 --- a/src/librustc_borrowck/borrowck/mir/gather_moves.rs +++ b/src/librustc_borrowck/borrowck/mir/gather_moves.rs @@ -10,7 +10,7 @@ use rustc::ty::{self, TyCtxt, ParameterEnvironment}; -use rustc::mir::repr::*; +use rustc::mir::*; use rustc::util::nodemap::FnvHashMap; use rustc_data_structures::indexed_vec::{IndexVec}; @@ -173,13 +173,7 @@ impl fmt::Debug for MoveOut { /// Tables mapping from an l-value to its MovePathIndex. #[derive(Debug)] pub struct MovePathLookup<'tcx> { - vars: IndexVec, - temps: IndexVec, - args: IndexVec, - - /// The move path representing the return value is constructed - /// lazily when we first encounter it in the input MIR. - return_ptr: Option, + locals: IndexVec, /// projections are made from a base-lvalue and a projection /// elem. The base-lvalue will have a unique MovePathIndex; we use @@ -218,16 +212,9 @@ impl<'a, 'tcx> MoveDataBuilder<'a, 'tcx> { moves: IndexVec::new(), loc_map: LocationMap::new(mir), rev_lookup: MovePathLookup { - vars: mir.var_decls.indices().map(Lvalue::Var).map(|v| { + locals: mir.local_decls.indices().map(Lvalue::Local).map(|v| { Self::new_move_path(&mut move_paths, &mut path_map, None, v) }).collect(), - temps: mir.temp_decls.indices().map(Lvalue::Temp).map(|t| { - Self::new_move_path(&mut move_paths, &mut path_map, None, t) - }).collect(), - args: mir.arg_decls.indices().map(Lvalue::Arg).map(|a| { - Self::new_move_path(&mut move_paths, &mut path_map, None, a) - }).collect(), - return_ptr: None, projections: FnvHashMap(), }, move_paths: move_paths, @@ -272,23 +259,9 @@ impl<'a, 'tcx> MoveDataBuilder<'a, 'tcx> { { debug!("lookup({:?})", lval); match *lval { - Lvalue::Var(var) => Ok(self.data.rev_lookup.vars[var]), - Lvalue::Arg(arg) => Ok(self.data.rev_lookup.args[arg]), - Lvalue::Temp(temp) => Ok(self.data.rev_lookup.temps[temp]), + Lvalue::Local(local) => Ok(self.data.rev_lookup.locals[local]), // error: can't move out of a static Lvalue::Static(..) => Err(MovePathError::IllegalMove), - Lvalue::ReturnPointer => match self.data.rev_lookup.return_ptr { - Some(ptr) => Ok(ptr), - ref mut ptr @ None => { - let path = Self::new_move_path( - &mut self.data.move_paths, - &mut self.data.path_map, - None, - lval.clone()); - *ptr = Some(path); - Ok(path) - } - }, Lvalue::Projection(ref proj) => { self.move_path_for_projection(lval, proj) } @@ -373,11 +346,8 @@ impl<'tcx> MovePathLookup<'tcx> { // parent. pub fn find(&self, lval: &Lvalue<'tcx>) -> LookupResult { match *lval { - Lvalue::Var(var) => LookupResult::Exact(self.vars[var]), - Lvalue::Temp(temp) => LookupResult::Exact(self.temps[temp]), - Lvalue::Arg(arg) => LookupResult::Exact(self.args[arg]), + Lvalue::Local(local) => LookupResult::Exact(self.locals[local]), Lvalue::Static(..) => LookupResult::Parent(None), - Lvalue::ReturnPointer => LookupResult::Exact(self.return_ptr.unwrap()), Lvalue::Projection(ref proj) => { match self.find(&proj.base) { LookupResult::Exact(base_path) => { @@ -486,7 +456,7 @@ impl<'a, 'tcx> MoveDataBuilder<'a, 'tcx> { TerminatorKind::Unreachable => { } TerminatorKind::Return => { - self.gather_move(loc, &Lvalue::ReturnPointer); + self.gather_move(loc, &Lvalue::Local(RETURN_POINTER)); } TerminatorKind::If { .. } | diff --git a/src/librustc_borrowck/borrowck/mir/mod.rs b/src/librustc_borrowck/borrowck/mir/mod.rs index f26afdc2b8..cea9170da9 100644 --- a/src/librustc_borrowck/borrowck/mir/mod.rs +++ b/src/librustc_borrowck/borrowck/mir/mod.rs @@ -17,8 +17,7 @@ use syntax_pos::{Span, DUMMY_SP}; use rustc::hir; use rustc::hir::intravisit::{FnKind}; -use rustc::mir::repr; -use rustc::mir::repr::{BasicBlock, BasicBlockData, Mir, Statement, Terminator, Location}; +use rustc::mir::{self, BasicBlock, BasicBlockData, Mir, Statement, Terminator, Location}; use rustc::session::Session; use rustc::ty::{self, TyCtxt}; @@ -56,15 +55,13 @@ pub struct MoveDataParamEnv<'tcx> { param_env: ty::ParameterEnvironment<'tcx>, } -pub fn borrowck_mir<'a, 'tcx: 'a>( - bcx: &mut BorrowckCtxt<'a, 'tcx>, - fk: FnKind, - _decl: &hir::FnDecl, - mir: &'a Mir<'tcx>, - body: &hir::Block, - _sp: Span, - id: ast::NodeId, - attributes: &[ast::Attribute]) { +pub fn borrowck_mir(bcx: &mut BorrowckCtxt, + fk: FnKind, + _decl: &hir::FnDecl, + body: &hir::Block, + _sp: Span, + id: ast::NodeId, + attributes: &[ast::Attribute]) { match fk { FnKind::ItemFn(name, ..) | FnKind::Method(name, ..) => { @@ -76,8 +73,10 @@ pub fn borrowck_mir<'a, 'tcx: 'a>( } let tcx = bcx.tcx; - let param_env = ty::ParameterEnvironment::for_item(tcx, id); + + let mir = &tcx.item_mir(tcx.map.local_def_id(id)); + let move_data = MoveData::gather_moves(mir, tcx, ¶m_env); let mdpe = MoveDataParamEnv { move_data: move_data, param_env: param_env }; let flow_inits = @@ -171,8 +170,8 @@ pub struct MirBorrowckCtxt<'b, 'a: 'b, 'tcx: 'a> { mir: &'b Mir<'tcx>, node_id: ast::NodeId, move_data: MoveData<'tcx>, - flow_inits: DataflowResults>, - flow_uninits: DataflowResults> + flow_inits: DataflowResults>, + flow_uninits: DataflowResults> } impl<'b, 'a: 'b, 'tcx: 'a> MirBorrowckCtxt<'b, 'a, 'tcx> { @@ -214,12 +213,12 @@ fn move_path_children_matching<'tcx, F>(move_data: &MoveData<'tcx>, path: MovePathIndex, mut cond: F) -> Option - where F: FnMut(&repr::LvalueProjection<'tcx>) -> bool + where F: FnMut(&mir::LvalueProjection<'tcx>) -> bool { let mut next_child = move_data.move_paths[path].first_child; while let Some(child_index) = next_child { match move_data.move_paths[child_index].lvalue { - repr::Lvalue::Projection(ref proj) => { + mir::Lvalue::Projection(ref proj) => { if cond(proj) { return Some(child_index) } @@ -252,7 +251,7 @@ fn move_path_children_matching<'tcx, F>(move_data: &MoveData<'tcx>, /// FIXME: we have to do something for moving slice patterns. fn lvalue_contents_drop_state_cannot_differ<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, mir: &Mir<'tcx>, - lv: &repr::Lvalue<'tcx>) -> bool { + lv: &mir::Lvalue<'tcx>) -> bool { let ty = lv.ty(mir, tcx).to_ty(tcx); match ty.sty { ty::TyArray(..) | ty::TySlice(..) | ty::TyRef(..) | ty::TyRawPtr(..) => { @@ -338,8 +337,8 @@ fn drop_flag_effects_for_function_entry<'a, 'tcx, F>( where F: FnMut(MovePathIndex, DropFlagState) { let move_data = &ctxt.move_data; - for (arg, _) in mir.arg_decls.iter_enumerated() { - let lvalue = repr::Lvalue::Arg(arg); + for arg in mir.args_iter() { + let lvalue = mir::Lvalue::Local(arg); let lookup_result = move_data.rev_lookup.find(&lvalue); on_lookup_result_bits(tcx, mir, move_data, lookup_result, @@ -379,23 +378,23 @@ fn drop_flag_effects_for_location<'a, 'tcx, F>( let block = &mir[loc.block]; match block.statements.get(loc.statement_index) { Some(stmt) => match stmt.kind { - repr::StatementKind::SetDiscriminant{ .. } => { + mir::StatementKind::SetDiscriminant{ .. } => { span_bug!(stmt.source_info.span, "SetDiscrimant should not exist during borrowck"); } - repr::StatementKind::Assign(ref lvalue, _) => { + mir::StatementKind::Assign(ref lvalue, _) => { debug!("drop_flag_effects: assignment {:?}", stmt); on_lookup_result_bits(tcx, mir, move_data, move_data.rev_lookup.find(lvalue), |moi| callback(moi, DropFlagState::Present)) } - repr::StatementKind::StorageLive(_) | - repr::StatementKind::StorageDead(_) | - repr::StatementKind::Nop => {} + mir::StatementKind::StorageLive(_) | + mir::StatementKind::StorageDead(_) | + mir::StatementKind::Nop => {} }, None => { debug!("drop_flag_effects: replace {:?}", block.terminator()); match block.terminator().kind { - repr::TerminatorKind::DropAndReplace { ref location, .. } => { + mir::TerminatorKind::DropAndReplace { ref location, .. } => { on_lookup_result_bits(tcx, mir, move_data, move_data.rev_lookup.find(location), |moi| callback(moi, DropFlagState::Present)) diff --git a/src/librustc_borrowck/borrowck/mir/patch.rs b/src/librustc_borrowck/borrowck/mir/patch.rs index 52cd1a9f94..19f240da73 100644 --- a/src/librustc_borrowck/borrowck/mir/patch.rs +++ b/src/librustc_borrowck/borrowck/mir/patch.rs @@ -9,7 +9,7 @@ // except according to those terms. use rustc::ty::Ty; -use rustc::mir::repr::*; +use rustc::mir::*; use rustc_data_structures::indexed_vec::{IndexVec, Idx}; /// This struct represents a patch to MIR, which can add @@ -19,9 +19,9 @@ pub struct MirPatch<'tcx> { patch_map: IndexVec>>, new_blocks: Vec>, new_statements: Vec<(Location, StatementKind<'tcx>)>, - new_temps: Vec>, + new_locals: Vec>, resume_block: BasicBlock, - next_temp: usize, + next_local: usize, } impl<'tcx> MirPatch<'tcx> { @@ -29,9 +29,9 @@ impl<'tcx> MirPatch<'tcx> { let mut result = MirPatch { patch_map: IndexVec::from_elem(None, mir.basic_blocks()), new_blocks: vec![], - new_temps: vec![], new_statements: vec![], - next_temp: mir.temp_decls.len(), + new_locals: vec![], + next_local: mir.local_decls.len(), resume_block: START_BLOCK }; @@ -92,11 +92,11 @@ impl<'tcx> MirPatch<'tcx> { } } - pub fn new_temp(&mut self, ty: Ty<'tcx>) -> Temp { - let index = self.next_temp; - self.next_temp += 1; - self.new_temps.push(TempDecl { ty: ty }); - Temp::new(index as usize) + pub fn new_temp(&mut self, ty: Ty<'tcx>) -> Local { + let index = self.next_local; + self.next_local += 1; + self.new_locals.push(LocalDecl::new_temp(ty)); + Local::new(index as usize) } pub fn new_block(&mut self, data: BasicBlockData<'tcx>) -> BasicBlock { @@ -124,11 +124,11 @@ impl<'tcx> MirPatch<'tcx> { pub fn apply(self, mir: &mut Mir<'tcx>) { debug!("MirPatch: {:?} new temps, starting from index {}: {:?}", - self.new_temps.len(), mir.temp_decls.len(), self.new_temps); + self.new_locals.len(), mir.local_decls.len(), self.new_locals); debug!("MirPatch: {} new blocks, starting from index {}", self.new_blocks.len(), mir.basic_blocks().len()); mir.basic_blocks_mut().extend(self.new_blocks); - mir.temp_decls.extend(self.new_temps); + mir.local_decls.extend(self.new_locals); for (src, patch) in self.patch_map.into_iter_enumerated() { if let Some(patch) = patch { debug!("MirPatch: patching block {:?}", src); diff --git a/src/librustc_borrowck/borrowck/mod.rs b/src/librustc_borrowck/borrowck/mod.rs index 5d62629b64..2f74ea3e47 100644 --- a/src/librustc_borrowck/borrowck/mod.rs +++ b/src/librustc_borrowck/borrowck/mod.rs @@ -51,8 +51,6 @@ use rustc::hir::{FnDecl, Block}; use rustc::hir::intravisit; use rustc::hir::intravisit::{Visitor, FnKind}; -use rustc::mir::mir_map::MirMap; - pub mod check_loans; pub mod gather_loans; @@ -102,10 +100,9 @@ impl<'a, 'tcx, 'v> Visitor<'v> for BorrowckCtxt<'a, 'tcx> { } } -pub fn check_crate<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, mir_map: &MirMap<'tcx>) { +pub fn check_crate<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>) { let mut bccx = BorrowckCtxt { tcx: tcx, - mir_map: Some(mir_map), free_region_map: FreeRegionMap::new(), stats: BorrowStats { loaned_paths_same: 0, @@ -168,12 +165,9 @@ fn borrowck_fn(this: &mut BorrowckCtxt, attributes: &[ast::Attribute]) { debug!("borrowck_fn(id={})", id); - let def_id = this.tcx.map.local_def_id(id); - if attributes.iter().any(|item| item.check_name("rustc_mir_borrowck")) { - let mir = this.mir_map.unwrap().map.get(&def_id).unwrap(); this.with_temp_region_map(id, |this| { - mir::borrowck_mir(this, fk, decl, mir, body, sp, id, attributes) + mir::borrowck_mir(this, fk, decl, body, sp, id, attributes) }); } @@ -249,7 +243,6 @@ fn build_borrowck_dataflow_data<'a, 'tcx>(this: &mut BorrowckCtxt<'a, 'tcx>, /// the `BorrowckCtxt` itself , e.g. the flowgraph visualizer. pub fn build_borrowck_dataflow_data_for_fn<'a, 'tcx>( tcx: TyCtxt<'a, 'tcx, 'tcx>, - mir_map: Option<&'a MirMap<'tcx>>, fn_parts: FnParts<'a>, cfg: &cfg::CFG) -> (BorrowckCtxt<'a, 'tcx>, AnalysisData<'a, 'tcx>) @@ -257,7 +250,6 @@ pub fn build_borrowck_dataflow_data_for_fn<'a, 'tcx>( let mut bccx = BorrowckCtxt { tcx: tcx, - mir_map: mir_map, free_region_map: FreeRegionMap::new(), stats: BorrowStats { loaned_paths_same: 0, @@ -297,10 +289,7 @@ pub struct BorrowckCtxt<'a, 'tcx: 'a> { free_region_map: FreeRegionMap, // Statistics: - stats: BorrowStats, - - // NodeId to MIR mapping (for methods that carry the #[rustc_mir] attribute). - mir_map: Option<&'a MirMap<'tcx>>, + stats: BorrowStats } #[derive(Clone)] @@ -311,8 +300,6 @@ struct BorrowStats { guaranteed_paths: usize } -pub type BckResult<'tcx, T> = Result>; - /////////////////////////////////////////////////////////////////////////// // Loans and loan paths @@ -1024,13 +1011,14 @@ impl<'a, 'tcx> BorrowckCtxt<'a, 'tcx> { } err_out_of_scope(super_scope, sub_scope, cause) => { - let (value_kind, value_msg) = match err.cmt.cat { + let (value_kind, value_msg, is_temporary) = match err.cmt.cat { mc::Categorization::Rvalue(_) => - ("temporary value", "temporary value created here"), + ("temporary value", "temporary value created here", true), _ => - ("borrowed value", "does not live long enough") + ("borrowed value", "does not live long enough", false) }; - match cause { + + let is_closure = match cause { euv::ClosureCapture(s) => { // The primary span starts out as the closure creation point. // Change the primary span here to highlight the use of the variable @@ -1041,24 +1029,52 @@ impl<'a, 'tcx> BorrowckCtxt<'a, 'tcx> { db.span = MultiSpan::from_span(s); db.span_label(primary, &format!("capture occurs here")); db.span_label(s, &value_msg); + true } - None => () + None => false } } _ => { db.span_label(error_span, &value_msg); + false } - } + }; let sub_span = self.region_end_span(sub_scope); let super_span = self.region_end_span(super_scope); match (sub_span, super_span) { (Some(s1), Some(s2)) if s1 == s2 => { - db.span_label(s1, &format!("{} dropped before borrower", value_kind)); + if !is_temporary && !is_closure { + db.span = MultiSpan::from_span(s1); + db.span_label(error_span, &format!("borrow occurs here")); + let msg = match opt_loan_path(&err.cmt) { + None => "borrowed value".to_string(), + Some(lp) => { + format!("`{}`", self.loan_path_to_string(&lp)) + } + }; + db.span_label(s1, + &format!("{} dropped here while still borrowed", msg)); + } else { + db.span_label(s1, &format!("{} dropped before borrower", value_kind)); + } db.note("values in a scope are dropped in the opposite order \ they are created"); } + (Some(s1), Some(s2)) if !is_temporary && !is_closure => { + db.span = MultiSpan::from_span(s2); + db.span_label(error_span, &format!("borrow occurs here")); + let msg = match opt_loan_path(&err.cmt) { + None => "borrowed value".to_string(), + Some(lp) => { + format!("`{}`", self.loan_path_to_string(&lp)) + } + }; + db.span_label(s2, + &format!("{} dropped here while still borrowed", msg)); + db.span_label(s1, &format!("{} needs to live until here", value_kind)); + } _ => { match sub_span { Some(s) => { diff --git a/src/librustc_borrowck/borrowck/move_data.rs b/src/librustc_borrowck/borrowck/move_data.rs index e9ba406389..ba036f1a8b 100644 --- a/src/librustc_borrowck/borrowck/move_data.rs +++ b/src/librustc_borrowck/borrowck/move_data.rs @@ -331,7 +331,7 @@ impl<'a, 'tcx> MoveData<'tcx> { fn existing_base_paths(&self, lp: &Rc>) -> Vec { - let mut result = vec!(); + let mut result = vec![]; self.add_existing_base_paths(lp, &mut result); result } diff --git a/src/librustc_borrowck/lib.rs b/src/librustc_borrowck/lib.rs index d3ab9c9318..2cd709dbd3 100644 --- a/src/librustc_borrowck/lib.rs +++ b/src/librustc_borrowck/lib.rs @@ -19,7 +19,7 @@ #![allow(non_camel_case_types)] -#![feature(dotdot_in_tuple_patterns)] +#![cfg_attr(stage0, feature(dotdot_in_tuple_patterns))] #![feature(quote)] #![feature(rustc_diagnostic_macros)] #![feature(rustc_private)] @@ -50,8 +50,6 @@ pub use borrowck::{AnalysisData, BorrowckCtxt, ElaborateDrops}; pub mod diagnostics; mod borrowck; -mod bitslice; -mod indexed_set; pub mod graphviz; diff --git a/src/librustc_const_eval/Cargo.toml b/src/librustc_const_eval/Cargo.toml index 8967672548..0e5cbce863 100644 --- a/src/librustc_const_eval/Cargo.toml +++ b/src/librustc_const_eval/Cargo.toml @@ -9,11 +9,13 @@ path = "lib.rs" crate-type = ["dylib"] [dependencies] +arena = { path = "../libarena" } log = { path = "../liblog" } serialize = { path = "../libserialize" } rustc = { path = "../librustc" } rustc_back = { path = "../librustc_back" } rustc_const_math = { path = "../librustc_const_math" } +rustc_data_structures = { path = "../librustc_data_structures" } rustc_errors = { path = "../librustc_errors" } syntax = { path = "../libsyntax" } graphviz = { path = "../libgraphviz" } diff --git a/src/librustc_const_eval/_match.rs b/src/librustc_const_eval/_match.rs new file mode 100644 index 0000000000..7f5eb31612 --- /dev/null +++ b/src/librustc_const_eval/_match.rs @@ -0,0 +1,767 @@ +// Copyright 2012-2016 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +use self::Constructor::*; +use self::Usefulness::*; +use self::WitnessPreference::*; + +use rustc::middle::const_val::ConstVal; +use eval::{compare_const_vals}; + +use rustc_const_math::ConstInt; + +use rustc_data_structures::fnv::FnvHashMap; +use rustc_data_structures::indexed_vec::Idx; + +use pattern::{FieldPattern, Pattern, PatternKind}; +use pattern::{PatternFoldable, PatternFolder}; + +use rustc::hir::def_id::{DefId}; +use rustc::hir::pat_util::def_to_path; +use rustc::ty::{self, Ty, TyCtxt, TypeFoldable}; + +use rustc::hir; +use rustc::hir::def::CtorKind; +use rustc::hir::{Pat, PatKind}; +use rustc::util::common::ErrorReported; + +use syntax::ast::{self, DUMMY_NODE_ID}; +use syntax::codemap::Spanned; +use syntax::ptr::P; +use syntax_pos::{Span, DUMMY_SP}; + +use arena::TypedArena; + +use std::cmp::Ordering; +use std::fmt; +use std::iter::{FromIterator, IntoIterator, repeat}; + +pub fn expand_pattern<'a, 'tcx>(cx: &MatchCheckCtxt<'a, 'tcx>, pat: Pattern<'tcx>) + -> &'a Pattern<'tcx> +{ + cx.pattern_arena.alloc(LiteralExpander.fold_pattern(&pat)) +} + +struct LiteralExpander; +impl<'tcx> PatternFolder<'tcx> for LiteralExpander { + fn fold_pattern(&mut self, pat: &Pattern<'tcx>) -> Pattern<'tcx> { + match (&pat.ty.sty, &*pat.kind) { + (&ty::TyRef(_, mt), &PatternKind::Constant { ref value }) => { + Pattern { + ty: pat.ty, + span: pat.span, + kind: box PatternKind::Deref { + subpattern: Pattern { + ty: mt.ty, + span: pat.span, + kind: box PatternKind::Constant { value: value.clone() }, + } + } + } + } + (_, &PatternKind::Binding { subpattern: Some(ref s), .. }) => { + s.fold_with(self) + } + _ => pat.super_fold_with(self) + } + } +} + +pub const DUMMY_WILD_PAT: &'static Pat = &Pat { + id: DUMMY_NODE_ID, + node: PatKind::Wild, + span: DUMMY_SP +}; + +impl<'tcx> Pattern<'tcx> { + fn is_wildcard(&self) -> bool { + match *self.kind { + PatternKind::Binding { subpattern: None, .. } | PatternKind::Wild => + true, + _ => false + } + } +} + +pub struct Matrix<'a, 'tcx: 'a>(Vec>>); + +impl<'a, 'tcx> Matrix<'a, 'tcx> { + pub fn empty() -> Self { + Matrix(vec![]) + } + + pub fn push(&mut self, row: Vec<&'a Pattern<'tcx>>) { + self.0.push(row) + } +} + +/// Pretty-printer for matrices of patterns, example: +/// ++++++++++++++++++++++++++ +/// + _ + [] + +/// ++++++++++++++++++++++++++ +/// + true + [First] + +/// ++++++++++++++++++++++++++ +/// + true + [Second(true)] + +/// ++++++++++++++++++++++++++ +/// + false + [_] + +/// ++++++++++++++++++++++++++ +/// + _ + [_, _, ..tail] + +/// ++++++++++++++++++++++++++ +impl<'a, 'tcx> fmt::Debug for Matrix<'a, 'tcx> { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + write!(f, "\n")?; + + let &Matrix(ref m) = self; + let pretty_printed_matrix: Vec> = m.iter().map(|row| { + row.iter().map(|pat| format!("{:?}", pat)).collect() + }).collect(); + + let column_count = m.iter().map(|row| row.len()).max().unwrap_or(0); + assert!(m.iter().all(|row| row.len() == column_count)); + let column_widths: Vec = (0..column_count).map(|col| { + 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 br = repeat('+').take(total_width).collect::(); + write!(f, "{}\n", br)?; + for row in pretty_printed_matrix { + write!(f, "+")?; + for (column, pat_str) in row.into_iter().enumerate() { + write!(f, " ")?; + write!(f, "{:1$}", pat_str, column_widths[column])?; + write!(f, " +")?; + } + write!(f, "\n")?; + write!(f, "{}\n", br)?; + } + Ok(()) + } +} + +impl<'a, 'tcx> FromIterator>> for Matrix<'a, 'tcx> { + fn from_iter>>>(iter: T) -> Self + { + Matrix(iter.into_iter().collect()) + } +} + +//NOTE: appears to be the only place other then InferCtxt to contain a ParamEnv +pub struct MatchCheckCtxt<'a, 'tcx: 'a> { + pub tcx: TyCtxt<'a, 'tcx, 'tcx>, + /// A wild pattern with an error type - it exists to avoid having to normalize + /// associated types to get field types. + pub wild_pattern: &'a Pattern<'tcx>, + pub pattern_arena: &'a TypedArena>, + pub byte_array_map: FnvHashMap<*const Pattern<'tcx>, Vec<&'a Pattern<'tcx>>>, +} + +impl<'a, 'tcx> MatchCheckCtxt<'a, 'tcx> { + pub fn create_and_enter( + tcx: TyCtxt<'a, 'tcx, 'tcx>, + f: F) -> R + where F: for<'b> FnOnce(MatchCheckCtxt<'b, 'tcx>) -> R + { + let wild_pattern = Pattern { + ty: tcx.types.err, + span: DUMMY_SP, + kind: box PatternKind::Wild + }; + + let pattern_arena = TypedArena::new(); + + f(MatchCheckCtxt { + tcx: tcx, + wild_pattern: &wild_pattern, + pattern_arena: &pattern_arena, + byte_array_map: FnvHashMap(), + }) + } + + // convert a byte-string pattern to a list of u8 patterns. + fn lower_byte_str_pattern(&mut self, pat: &'a Pattern<'tcx>) -> Vec<&'a Pattern<'tcx>> { + let pattern_arena = &*self.pattern_arena; + let tcx = self.tcx; + self.byte_array_map.entry(pat).or_insert_with(|| { + match pat.kind { + box PatternKind::Constant { + value: ConstVal::ByteStr(ref data) + } => { + data.iter().map(|c| &*pattern_arena.alloc(Pattern { + ty: tcx.types.u8, + span: pat.span, + kind: box PatternKind::Constant { + value: ConstVal::Integral(ConstInt::U8(*c)) + } + })).collect() + } + _ => span_bug!(pat.span, "unexpected byte array pattern {:?}", pat) + } + }).clone() + } +} + +#[derive(Clone, Debug, PartialEq)] +pub enum Constructor { + /// The constructor of all patterns that don't vary by constructor, + /// e.g. struct patterns and fixed-length arrays. + Single, + /// Enum variants. + Variant(DefId), + /// Literal values. + ConstantValue(ConstVal), + /// Ranges of literal values (2..5). + ConstantRange(ConstVal, ConstVal), + /// Array patterns of length n. + Slice(usize), +} + +impl Constructor { + fn variant_for_adt<'tcx, 'container, 'a>(&self, + adt: &'a ty::AdtDefData<'tcx, 'container>) + -> &'a ty::VariantDefData<'tcx, 'container> { + match self { + &Variant(vid) => adt.variant_with_id(vid), + &Single => { + assert_eq!(adt.variants.len(), 1); + &adt.variants[0] + } + _ => bug!("bad constructor {:?} for adt {:?}", self, adt) + } + } +} + +#[derive(Clone, PartialEq)] +pub enum Usefulness { + Useful, + UsefulWithWitness(Vec), + NotUseful +} + +#[derive(Copy, Clone)] +pub enum WitnessPreference { + ConstructWitness, + LeaveOutWitness +} + +#[derive(Copy, Clone, Debug)] +struct PatternContext<'tcx> { + ty: Ty<'tcx>, + max_slice_length: usize, +} + + +fn const_val_to_expr(value: &ConstVal) -> P { + let node = match value { + &ConstVal::Bool(b) => ast::LitKind::Bool(b), + _ => bug!() + }; + P(hir::Expr { + id: DUMMY_NODE_ID, + node: hir::ExprLit(P(Spanned { node: node, span: DUMMY_SP })), + span: DUMMY_SP, + attrs: ast::ThinVec::new(), + }) +} + +/// A stack of patterns in reverse order of construction +#[derive(Clone, PartialEq, Eq)] +pub struct Witness(Vec>); + +impl Witness { + pub fn single_pattern(&self) -> &Pat { + assert_eq!(self.0.len(), 1); + &self.0[0] + } + + fn push_wild_constructor<'a, 'tcx>( + mut self, + cx: &MatchCheckCtxt<'a, 'tcx>, + ctor: &Constructor, + ty: Ty<'tcx>) + -> Self + { + let arity = constructor_arity(cx, ctor, ty); + self.0.extend(repeat(DUMMY_WILD_PAT).take(arity).map(|p| P(p.clone()))); + self.apply_constructor(cx, ctor, ty) + } + + + /// Constructs a partial witness for a pattern given a list of + /// patterns expanded by the specialization step. + /// + /// When a pattern P is discovered to be useful, this function is used bottom-up + /// to reconstruct a complete witness, e.g. a pattern P' that covers a subset + /// of values, V, where each value in that set is not covered by any previously + /// used patterns and is covered by the pattern P'. Examples: + /// + /// left_ty: tuple of 3 elements + /// pats: [10, 20, _] => (10, 20, _) + /// + /// left_ty: struct X { a: (bool, &'static str), b: usize} + /// pats: [(false, "foo"), 42] => X { a: (false, "foo"), b: 42 } + fn apply_constructor<'a, 'tcx>( + mut self, + cx: &MatchCheckCtxt<'a,'tcx>, + ctor: &Constructor, + ty: Ty<'tcx>) + -> Self + { + let arity = constructor_arity(cx, ctor, ty); + let pat = { + let len = self.0.len(); + let mut pats = self.0.drain(len-arity..).rev(); + + match ty.sty { + ty::TyTuple(..) => PatKind::Tuple(pats.collect(), None), + + ty::TyAdt(adt, _) => { + let v = ctor.variant_for_adt(adt); + match v.ctor_kind { + CtorKind::Fictive => { + let field_pats: hir::HirVec<_> = v.fields.iter() + .zip(pats) + .filter(|&(_, ref pat)| pat.node != PatKind::Wild) + .map(|(field, pat)| Spanned { + span: DUMMY_SP, + node: hir::FieldPat { + name: field.name, + pat: pat, + is_shorthand: false, + } + }).collect(); + let has_more_fields = field_pats.len() < arity; + PatKind::Struct( + def_to_path(cx.tcx, v.did), field_pats, has_more_fields) + } + CtorKind::Fn => { + PatKind::TupleStruct( + def_to_path(cx.tcx, v.did), pats.collect(), None) + } + CtorKind::Const => { + PatKind::Path(None, def_to_path(cx.tcx, v.did)) + } + } + } + + ty::TyRef(_, ty::TypeAndMut { mutbl, .. }) => { + PatKind::Ref(pats.nth(0).unwrap(), mutbl) + } + + ty::TySlice(_) | ty::TyArray(..) => { + PatKind::Slice(pats.collect(), None, hir::HirVec::new()) + } + + _ => { + match *ctor { + ConstantValue(ref v) => PatKind::Lit(const_val_to_expr(v)), + _ => PatKind::Wild, + } + } + } + }; + + self.0.push(P(hir::Pat { + id: DUMMY_NODE_ID, + node: pat, + span: DUMMY_SP + })); + + self + } +} + +/// Return the set of constructors from the same type as the first column of `matrix`, +/// that are matched only by wildcard patterns from that first column. +/// +/// Therefore, if there is some pattern that is unmatched by `matrix`, it will +/// still be unmatched if the first constructor is replaced by any of the constructors +/// in the return value. +fn missing_constructors(cx: &mut MatchCheckCtxt, + matrix: &Matrix, + pcx: PatternContext) -> Vec { + let used_constructors: Vec = + matrix.0.iter() + .flat_map(|row| pat_constructors(cx, row[0], pcx).unwrap_or(vec![])) + .collect(); + debug!("used_constructors = {:?}", used_constructors); + all_constructors(cx, pcx).into_iter() + .filter(|c| !used_constructors.contains(c)) + .collect() +} + +/// This determines the set of all possible constructors of a pattern matching +/// values of type `left_ty`. For vectors, this would normally be an infinite set +/// +/// This intentionally does not list ConstantValue specializations for +/// non-booleans, because we currently assume that there is always a +/// "non-standard constant" that matches. See issue #12483. +/// +/// but is instead bounded by the maximum fixed length of slice patterns in +/// the column of patterns being analyzed. +fn all_constructors(_cx: &mut MatchCheckCtxt, pcx: PatternContext) -> Vec { + match pcx.ty.sty { + ty::TyBool => + [true, false].iter().map(|b| ConstantValue(ConstVal::Bool(*b))).collect(), + ty::TySlice(_) => + (0..pcx.max_slice_length+1).map(|length| Slice(length)).collect(), + ty::TyArray(_, length) => vec![Slice(length)], + ty::TyAdt(def, _) if def.is_enum() && def.variants.len() > 1 => + def.variants.iter().map(|v| Variant(v.did)).collect(), + _ => vec![Single] + } +} + +/// Algorithm from http://moscova.inria.fr/~maranget/papers/warn/index.html +/// +/// Whether a vector `v` of patterns is 'useful' in relation to a set of such +/// vectors `m` is defined as there being a set of inputs that will match `v` +/// but not any of the sets in `m`. +/// +/// This is used both for reachability checking (if a pattern isn't useful in +/// relation to preceding patterns, it is not reachable) and exhaustiveness +/// checking (if a wildcard pattern is useful in relation to a matrix, the +/// matrix isn't exhaustive). +/// +/// Note: is_useful doesn't work on empty types, as the paper notes. +/// So it assumes that v is non-empty. +pub fn is_useful<'a, 'tcx>(cx: &mut MatchCheckCtxt<'a, 'tcx>, + matrix: &Matrix<'a, 'tcx>, + v: &[&'a Pattern<'tcx>], + witness: WitnessPreference) + -> Usefulness { + let &Matrix(ref rows) = matrix; + debug!("is_useful({:?}, {:?})", matrix, v); + if rows.is_empty() { + return match witness { + ConstructWitness => UsefulWithWitness(vec![Witness( + repeat(DUMMY_WILD_PAT).take(v.len()).map(|p| P(p.clone())).collect() + )]), + LeaveOutWitness => Useful + }; + } + if rows[0].is_empty() { + return NotUseful; + } + + let &Matrix(ref rows) = matrix; + assert!(rows.iter().all(|r| r.len() == v.len())); + let pcx = PatternContext { + ty: rows.iter().map(|r| r[0].ty).find(|ty| !ty.references_error()) + .unwrap_or(v[0].ty), + max_slice_length: rows.iter().filter_map(|row| match *row[0].kind { + PatternKind::Slice { ref prefix, slice: _, ref suffix } => + Some(prefix.len() + suffix.len()), + PatternKind::Constant { value: ConstVal::ByteStr(ref data) } => + Some(data.len()), + _ => None + }).max().map_or(0, |v| v + 1) + }; + + debug!("is_useful_expand_first_col: pcx={:?}, expanding {:?}", pcx, v[0]); + + if let Some(constructors) = pat_constructors(cx, v[0], pcx) { + debug!("is_useful - expanding constructors: {:?}", constructors); + constructors.into_iter().map(|c| + is_useful_specialized(cx, matrix, v, c.clone(), pcx.ty, witness) + ).find(|result| result != &NotUseful).unwrap_or(NotUseful) + } else { + debug!("is_useful - expanding wildcard"); + let constructors = missing_constructors(cx, matrix, pcx); + debug!("is_useful - missing_constructors = {:?}", constructors); + if constructors.is_empty() { + all_constructors(cx, pcx).into_iter().map(|c| { + is_useful_specialized(cx, matrix, v, c.clone(), pcx.ty, witness) + }).find(|result| result != &NotUseful).unwrap_or(NotUseful) + } else { + let matrix = rows.iter().filter_map(|r| { + if r[0].is_wildcard() { + Some(r[1..].to_vec()) + } else { + None + } + }).collect(); + match is_useful(cx, &matrix, &v[1..], witness) { + UsefulWithWitness(pats) => { + let cx = &*cx; + UsefulWithWitness(pats.into_iter().flat_map(|witness| { + constructors.iter().map(move |ctor| { + witness.clone().push_wild_constructor(cx, ctor, pcx.ty) + }) + }).collect()) + } + result => result + } + } + } +} + +fn is_useful_specialized<'a, 'tcx>( + cx: &mut MatchCheckCtxt<'a, 'tcx>, + &Matrix(ref m): &Matrix<'a, 'tcx>, + v: &[&'a Pattern<'tcx>], + ctor: Constructor, + lty: Ty<'tcx>, + witness: WitnessPreference) -> Usefulness +{ + let arity = constructor_arity(cx, &ctor, lty); + let matrix = Matrix(m.iter().flat_map(|r| { + specialize(cx, &r[..], &ctor, 0, arity) + }).collect()); + match specialize(cx, v, &ctor, 0, arity) { + Some(v) => match is_useful(cx, &matrix, &v[..], witness) { + UsefulWithWitness(witnesses) => UsefulWithWitness( + witnesses.into_iter() + .map(|witness| witness.apply_constructor(cx, &ctor, lty)) + .collect() + ), + result => result + }, + None => NotUseful + } +} + +/// Determines the constructors that the given pattern can be specialized to. +/// +/// In most cases, there's only one constructor that a specific pattern +/// represents, such as a specific enum variant or a specific literal value. +/// Slice patterns, however, can match slices of different lengths. For instance, +/// `[a, b, ..tail]` can match a slice of length 2, 3, 4 and so on. +/// +/// Returns None in case of a catch-all, which can't be specialized. +fn pat_constructors(_cx: &mut MatchCheckCtxt, + pat: &Pattern, + pcx: PatternContext) + -> Option> +{ + match *pat.kind { + PatternKind::Binding { .. } | PatternKind::Wild => + None, + PatternKind::Leaf { .. } | PatternKind::Deref { .. } => + Some(vec![Single]), + PatternKind::Variant { adt_def, variant_index, .. } => + Some(vec![Variant(adt_def.variants[variant_index].did)]), + PatternKind::Constant { ref value } => + Some(vec![ConstantValue(value.clone())]), + PatternKind::Range { ref lo, ref hi } => + Some(vec![ConstantRange(lo.clone(), hi.clone())]), + PatternKind::Array { .. } => match pcx.ty.sty { + ty::TyArray(_, length) => Some(vec![Slice(length)]), + _ => span_bug!(pat.span, "bad ty {:?} for array pattern", pcx.ty) + }, + PatternKind::Slice { ref prefix, ref slice, ref suffix } => { + let pat_len = prefix.len() + suffix.len(); + if slice.is_some() { + Some((pat_len..pcx.max_slice_length+1).map(Slice).collect()) + } else { + Some(vec![Slice(pat_len)]) + } + } + } +} + +/// This computes the arity of a constructor. The arity of a constructor +/// is how many subpattern patterns of that constructor should be expanded to. +/// +/// For instance, a tuple pattern (_, 42, Some([])) has the arity of 3. +/// A struct pattern's arity is the number of fields it contains, etc. +fn constructor_arity(_cx: &MatchCheckCtxt, ctor: &Constructor, ty: Ty) -> usize { + debug!("constructor_arity({:?}, {:?})", ctor, ty); + match ty.sty { + ty::TyTuple(ref fs) => fs.len(), + ty::TyBox(_) => 1, + ty::TySlice(..) | ty::TyArray(..) => match *ctor { + Slice(length) => length, + ConstantValue(_) => 0, + _ => bug!("bad slice pattern {:?} {:?}", ctor, ty) + }, + ty::TyRef(..) => 1, + ty::TyAdt(adt, _) => { + ctor.variant_for_adt(adt).fields.len() + } + _ => 0 + } +} + +fn slice_pat_covered_by_constructor(_tcx: TyCtxt, _span: Span, + ctor: &Constructor, + prefix: &[Pattern], + slice: &Option, + suffix: &[Pattern]) + -> Result { + let data = match *ctor { + ConstantValue(ConstVal::ByteStr(ref data)) => data, + _ => bug!() + }; + + let pat_len = prefix.len() + suffix.len(); + if data.len() < pat_len || (slice.is_none() && data.len() > pat_len) { + return Ok(false); + } + + for (ch, pat) in + data[..prefix.len()].iter().zip(prefix).chain( + data[data.len()-suffix.len()..].iter().zip(suffix)) + { + match pat.kind { + box PatternKind::Constant { ref value } => match *value { + ConstVal::Integral(ConstInt::U8(u)) => { + if u != *ch { + return Ok(false); + } + }, + _ => span_bug!(pat.span, "bad const u8 {:?}", value) + }, + _ => {} + } + } + + Ok(true) +} + +fn range_covered_by_constructor(tcx: TyCtxt, span: Span, + ctor: &Constructor, + from: &ConstVal, to: &ConstVal) + -> Result { + let (c_from, c_to) = match *ctor { + ConstantValue(ref value) => (value, value), + ConstantRange(ref from, ref to) => (from, to), + Single => return Ok(true), + _ => bug!() + }; + let cmp_from = compare_const_vals(tcx, span, c_from, from)?; + let cmp_to = compare_const_vals(tcx, span, c_to, to)?; + Ok(cmp_from != Ordering::Less && cmp_to != Ordering::Greater) +} + +fn patterns_for_variant<'a, 'tcx>( + cx: &mut MatchCheckCtxt<'a, 'tcx>, + subpatterns: &'a [FieldPattern<'tcx>], + arity: usize) + -> Vec<&'a Pattern<'tcx>> +{ + let mut result = vec![cx.wild_pattern; arity]; + + for subpat in subpatterns { + result[subpat.field.index()] = &subpat.pattern; + } + + debug!("patterns_for_variant({:?}, {:?}) = {:?}", subpatterns, arity, result); + result +} + +/// This is the main specialization step. It expands the first pattern in the given row +/// into `arity` patterns based on the constructor. For most patterns, the step is trivial, +/// for instance tuple patterns are flattened and box patterns expand into their inner pattern. +/// +/// OTOH, slice patterns with a subslice pattern (..tail) can be expanded into multiple +/// different patterns. +/// Structure patterns with a partial wild pattern (Foo { a: 42, .. }) have their missing +/// fields filled with wild patterns. +fn specialize<'a, 'tcx>( + cx: &mut MatchCheckCtxt<'a, 'tcx>, + r: &[&'a Pattern<'tcx>], + constructor: &Constructor, col: usize, arity: usize) + -> Option>> +{ + let pat = &r[col]; + + let head: Option> = match *pat.kind { + PatternKind::Binding { .. } | PatternKind::Wild => + Some(vec![cx.wild_pattern; arity]), + + PatternKind::Variant { adt_def, variant_index, ref subpatterns } => { + let ref variant = adt_def.variants[variant_index]; + if *constructor == Variant(variant.did) { + Some(patterns_for_variant(cx, subpatterns, arity)) + } else { + None + } + } + + PatternKind::Leaf { ref subpatterns } => Some(patterns_for_variant(cx, subpatterns, arity)), + PatternKind::Deref { ref subpattern } => Some(vec![subpattern]), + + PatternKind::Constant { ref value } => { + match *constructor { + Slice(..) => match *value { + ConstVal::ByteStr(ref data) => { + if arity == data.len() { + Some(cx.lower_byte_str_pattern(pat)) + } else { + None + } + } + _ => span_bug!(pat.span, + "unexpected const-val {:?} with ctor {:?}", value, constructor) + }, + _ => { + match range_covered_by_constructor( + cx.tcx, pat.span, constructor, value, value + ) { + Ok(true) => Some(vec![]), + Ok(false) => None, + Err(ErrorReported) => None, + } + } + } + } + + PatternKind::Range { ref lo, ref hi } => { + match range_covered_by_constructor( + cx.tcx, pat.span, constructor, lo, hi + ) { + Ok(true) => Some(vec![]), + Ok(false) => None, + Err(ErrorReported) => None, + } + } + + PatternKind::Array { ref prefix, ref slice, ref suffix } | + PatternKind::Slice { ref prefix, ref slice, ref suffix } => { + match *constructor { + Slice(..) => { + let pat_len = prefix.len() + suffix.len(); + if let Some(slice_count) = arity.checked_sub(pat_len) { + if slice_count == 0 || slice.is_some() { + Some( + prefix.iter().chain( + repeat(cx.wild_pattern).take(slice_count).chain( + suffix.iter() + )).collect()) + } else { + None + } + } else { + None + } + } + ConstantValue(..) => { + match slice_pat_covered_by_constructor( + cx.tcx, pat.span, constructor, prefix, slice, suffix + ) { + Ok(true) => Some(vec![]), + Ok(false) => None, + Err(ErrorReported) => None + } + } + _ => span_bug!(pat.span, + "unexpected ctor {:?} for slice pat", constructor) + } + } + }; + debug!("specialize({:?}, {:?}) = {:?}", r[col], arity, head); + + head.map(|mut head| { + head.extend_from_slice(&r[..col]); + head.extend_from_slice(&r[col + 1..]); + head + }) +} diff --git a/src/librustc_const_eval/check_match.rs b/src/librustc_const_eval/check_match.rs index eb74936d8c..615aca90db 100644 --- a/src/librustc_const_eval/check_match.rs +++ b/src/librustc_const_eval/check_match.rs @@ -8,219 +8,210 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -use self::Constructor::*; -use self::Usefulness::*; -use self::WitnessPreference::*; +use _match::{MatchCheckCtxt, Matrix, expand_pattern, is_useful}; +use _match::{DUMMY_WILD_PAT}; +use _match::Usefulness::*; +use _match::WitnessPreference::*; + +use pattern::{Pattern, PatternContext, PatternError}; -use rustc::dep_graph::DepNode; -use rustc::middle::const_val::ConstVal; -use ::{eval_const_expr, eval_const_expr_partial, compare_const_vals}; -use ::{const_expr_to_pat, lookup_const_by_id}; -use ::EvalHint::ExprTypeChecked; use eval::report_const_eval_err; -use rustc::hir::def::*; -use rustc::hir::def_id::{DefId}; + +use rustc::dep_graph::DepNode; + +use rustc::hir::pat_util::{pat_bindings, pat_contains_bindings}; + use rustc::middle::expr_use_visitor::{ConsumeMode, Delegate, ExprUseVisitor}; use rustc::middle::expr_use_visitor::{LoanCause, MutateMode}; use rustc::middle::expr_use_visitor as euv; use rustc::middle::mem_categorization::{cmt}; -use rustc::hir::pat_util::*; +use rustc::session::Session; use rustc::traits::Reveal; -use rustc::ty::{self, Ty, TyCtxt}; -use std::cmp::Ordering; -use std::fmt; -use std::iter::{FromIterator, IntoIterator, repeat}; +use rustc::ty::{self, TyCtxt}; +use rustc_errors::DiagnosticBuilder; -use rustc::hir; -use rustc::hir::{Pat, PatKind}; +use rustc::hir::def::*; use rustc::hir::intravisit::{self, Visitor, FnKind}; -use rustc_back::slice; - -use syntax::ast::{self, DUMMY_NODE_ID, NodeId}; -use syntax::codemap::Spanned; -use syntax_pos::{Span, DUMMY_SP}; use rustc::hir::print::pat_to_string; -use syntax::ptr::P; -use syntax::util::move_map::MoveMap; -use rustc::util::common::ErrorReported; +use rustc::hir::{self, Pat, PatKind}; -pub const DUMMY_WILD_PAT: &'static Pat = &Pat { - id: DUMMY_NODE_ID, - node: PatKind::Wild, - span: DUMMY_SP -}; - -struct Matrix<'a, 'tcx>(Vec>)>>); +use rustc_back::slice; -/// Pretty-printer for matrices of patterns, example: -/// ++++++++++++++++++++++++++ -/// + _ + [] + -/// ++++++++++++++++++++++++++ -/// + true + [First] + -/// ++++++++++++++++++++++++++ -/// + true + [Second(true)] + -/// ++++++++++++++++++++++++++ -/// + false + [_] + -/// ++++++++++++++++++++++++++ -/// + _ + [_, _, ..tail] + -/// ++++++++++++++++++++++++++ -impl<'a, 'tcx> fmt::Debug for Matrix<'a, 'tcx> { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - write!(f, "\n")?; +use syntax::ast; +use syntax::ptr::P; +use syntax_pos::Span; - let &Matrix(ref m) = self; - let pretty_printed_matrix: Vec> = m.iter().map(|row| { - row.iter() - .map(|&(pat,ty)| format!("{}: {:?}", pat_to_string(&pat), ty)) - .collect::>() - }).collect(); +struct OuterVisitor<'a, 'tcx: 'a> { tcx: TyCtxt<'a, 'tcx, 'tcx> } - let column_count = m.iter().map(|row| row.len()).max().unwrap_or(0); - assert!(m.iter().all(|row| row.len() == column_count)); - let column_widths: Vec = (0..column_count).map(|col| { - pretty_printed_matrix.iter().map(|row| row[col].len()).max().unwrap_or(0) - }).collect(); +impl<'a, 'v, 'tcx> Visitor<'v> for OuterVisitor<'a, 'tcx> { + fn visit_expr(&mut self, _expr: &hir::Expr) { + return // const, static and N in [T; N] - shouldn't contain anything + } - let total_width = column_widths.iter().cloned().sum::() + column_count * 3 + 1; - let br = repeat('+').take(total_width).collect::(); - write!(f, "{}\n", br)?; - for row in pretty_printed_matrix { - write!(f, "+")?; - for (column, pat_str) in row.into_iter().enumerate() { - write!(f, " ")?; - write!(f, "{:1$}", pat_str, column_widths[column])?; - write!(f, " +")?; - } - write!(f, "\n")?; - write!(f, "{}\n", br)?; + fn visit_trait_item(&mut self, item: &hir::TraitItem) { + if let hir::ConstTraitItem(..) = item.node { + return // nothing worth match checking in a constant + } else { + intravisit::walk_trait_item(self, item); } - Ok(()) } -} -impl<'a, 'tcx> FromIterator>)>> for Matrix<'a, 'tcx> { - fn from_iter>)>>>(iter: T) - -> Self - { - Matrix(iter.into_iter().collect()) + fn visit_impl_item(&mut self, item: &hir::ImplItem) { + if let hir::ImplItemKind::Const(..) = item.node { + return // nothing worth match checking in a constant + } else { + intravisit::walk_impl_item(self, item); + } } -} -//NOTE: appears to be the only place other then InferCtxt to contain a ParamEnv -pub struct MatchCheckCtxt<'a, 'tcx: 'a> { - pub tcx: TyCtxt<'a, 'tcx, 'tcx>, - pub param_env: ty::ParameterEnvironment<'tcx>, + fn visit_fn(&mut self, fk: FnKind<'v>, fd: &'v hir::FnDecl, + b: &'v hir::Block, s: Span, id: ast::NodeId) { + if let FnKind::Closure(..) = fk { + span_bug!(s, "check_match: closure outside of function") + } + + MatchVisitor { + tcx: self.tcx, + param_env: &ty::ParameterEnvironment::for_item(self.tcx, id) + }.visit_fn(fk, fd, b, s, id); + } } -#[derive(Clone, Debug, PartialEq)] -pub enum Constructor { - /// The constructor of all patterns that don't vary by constructor, - /// e.g. struct patterns and fixed-length arrays. - Single, - /// Enum variants. - Variant(DefId), - /// Literal values. - ConstantValue(ConstVal), - /// Ranges of literal values (2..5). - ConstantRange(ConstVal, ConstVal), - /// Array patterns of length n. - Slice(usize), - /// Array patterns with a subslice. - SliceWithSubslice(usize, usize) +pub fn check_crate<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>) { + tcx.visit_all_items_in_krate(DepNode::MatchCheck, &mut OuterVisitor { tcx: tcx }); + tcx.sess.abort_if_errors(); } -#[derive(Clone, PartialEq)] -enum Usefulness { - Useful, - UsefulWithWitness(Vec>), - NotUseful +fn create_e0004<'a>(sess: &'a Session, sp: Span, error_message: String) -> DiagnosticBuilder<'a> { + struct_span_err!(sess, sp, E0004, "{}", &error_message) } -#[derive(Copy, Clone)] -enum WitnessPreference { - ConstructWitness, - LeaveOutWitness +struct MatchVisitor<'a, 'tcx: 'a> { + tcx: TyCtxt<'a, 'tcx, 'tcx>, + param_env: &'a ty::ParameterEnvironment<'tcx> } -impl<'a, 'tcx, 'v> Visitor<'v> for MatchCheckCtxt<'a, 'tcx> { +impl<'a, 'tcx, 'v> Visitor<'v> for MatchVisitor<'a, 'tcx> { fn visit_expr(&mut self, ex: &hir::Expr) { - check_expr(self, ex); + intravisit::walk_expr(self, ex); + + match ex.node { + hir::ExprMatch(ref scrut, ref arms, source) => { + self.check_match(scrut, arms, source, ex.span); + } + _ => {} + } } - fn visit_local(&mut self, l: &hir::Local) { - check_local(self, l); + + fn visit_local(&mut self, loc: &hir::Local) { + intravisit::walk_local(self, loc); + + self.check_irrefutable(&loc.pat, false); + + // Check legality of move bindings and `@` patterns. + self.check_patterns(false, slice::ref_slice(&loc.pat)); } + fn visit_fn(&mut self, fk: FnKind<'v>, fd: &'v hir::FnDecl, - b: &'v hir::Block, s: Span, n: NodeId) { - check_fn(self, fk, fd, b, s, n); - } -} + b: &'v hir::Block, s: Span, n: ast::NodeId) { + intravisit::walk_fn(self, fk, fd, b, s, n); -pub fn check_crate<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>) { - tcx.visit_all_items_in_krate(DepNode::MatchCheck, &mut MatchCheckCtxt { - tcx: tcx, - param_env: tcx.empty_parameter_environment(), - }); - tcx.sess.abort_if_errors(); + for input in &fd.inputs { + self.check_irrefutable(&input.pat, true); + self.check_patterns(false, slice::ref_slice(&input.pat)); + } + } } -fn check_expr(cx: &mut MatchCheckCtxt, ex: &hir::Expr) { - intravisit::walk_expr(cx, ex); - match ex.node { - hir::ExprMatch(ref scrut, ref arms, source) => { - for arm in arms { - // First, check legality of move bindings. - check_legality_of_move_bindings(cx, - arm.guard.is_some(), - &arm.pats); +impl<'a, 'tcx> MatchVisitor<'a, 'tcx> { + fn check_patterns(&self, has_guard: bool, pats: &[P]) { + check_legality_of_move_bindings(self, has_guard, pats); + for pat in pats { + check_legality_of_bindings_in_at_patterns(self, pat); + } + } - // Second, if there is a guard on each arm, make sure it isn't - // assigning or borrowing anything mutably. - if let Some(ref guard) = arm.guard { - check_for_mutation_in_guard(cx, &guard); + fn report_inlining_errors(&self, patcx: PatternContext, pat_span: Span) { + for error in patcx.errors { + match error { + PatternError::BadConstInPattern(span, def_id) => { + self.tcx.sess.span_err( + span, + &format!("constants of the type `{}` \ + cannot be used in patterns", + self.tcx.item_path_str(def_id))); + } + PatternError::StaticInPattern(span) => { + span_err!(self.tcx.sess, span, E0158, + "statics cannot be referenced in patterns"); + } + PatternError::ConstEval(err) => { + report_const_eval_err(self.tcx, &err, pat_span, "pattern").emit(); } } + } + } - let mut static_inliner = StaticInliner::new(cx.tcx); - let inlined_arms = arms.iter().map(|arm| { - (arm.pats.iter().map(|pat| { - static_inliner.fold_pat((*pat).clone()) - }).collect(), arm.guard.as_ref().map(|e| &**e)) - }).collect::>, Option<&hir::Expr>)>>(); + fn check_match( + &self, + scrut: &hir::Expr, + arms: &[hir::Arm], + source: hir::MatchSource, + span: Span) + { + for arm in arms { + // First, check legality of move bindings. + self.check_patterns(arm.guard.is_some(), &arm.pats); + + // Second, if there is a guard on each arm, make sure it isn't + // assigning or borrowing anything mutably. + if let Some(ref guard) = arm.guard { + check_for_mutation_in_guard(self, &guard); + } - // Bail out early if inlining failed. - if static_inliner.failed { - return; + // Third, perform some lints. + for pat in &arm.pats { + check_for_bindings_named_the_same_as_variants(self, pat); } + } - for pat in inlined_arms - .iter() - .flat_map(|&(ref pats, _)| pats) { - // Third, check legality of move bindings. - check_legality_of_bindings_in_at_patterns(cx, &pat); + MatchCheckCtxt::create_and_enter(self.tcx, |ref mut cx| { + let mut have_errors = false; - // Fourth, check if there are any references to NaN that we should warn about. - check_for_static_nan(cx, &pat); + let inlined_arms : Vec<(Vec<_>, _)> = arms.iter().map(|arm| ( + arm.pats.iter().map(|pat| { + let mut patcx = PatternContext::new(self.tcx); + let pattern = expand_pattern(cx, patcx.lower_pattern(&pat)); + if !patcx.errors.is_empty() { + self.report_inlining_errors(patcx, pat.span); + have_errors = true; + } + (pattern, &**pat) + }).collect(), + arm.guard.as_ref().map(|e| &**e) + )).collect(); - // Fifth, check if for any of the patterns that match an enumerated type - // are bindings with the same name as one of the variants of said type. - check_for_bindings_named_the_same_as_variants(cx, &pat); + // Bail out early if inlining failed. + if have_errors { + return; } // Fourth, check for unreachable arms. - check_arms(cx, &inlined_arms[..], source); + check_arms(cx, &inlined_arms, source); // Finally, check if the whole match expression is exhaustive. // Check for empty enum, because is_useful only works on inhabited types. - let pat_ty = cx.tcx.node_id_to_type(scrut.id); + let pat_ty = self.tcx.tables().node_id_to_type(scrut.id); if inlined_arms.is_empty() { - if !pat_ty.is_uninhabited(cx.tcx) { + if !pat_ty.is_uninhabited(self.tcx) { // We know the type is inhabited, so this must be wrong - let mut err = struct_span_err!(cx.tcx.sess, ex.span, E0002, - "non-exhaustive patterns: type {} is non-empty", - pat_ty); - span_help!(&mut err, ex.span, - "Please ensure that all possible cases are being handled; \ - possibly adding wildcards or more match arms."); + let mut err = create_e0004(self.tcx.sess, span, + format!("non-exhaustive patterns: type {} \ + is non-empty", + pat_ty)); + span_help!(&mut err, span, + "Please ensure that all possible cases are being handled; \ + possibly adding wildcards or more match arms."); err.emit(); } // If the type *is* uninhabited, it's vacuously exhaustive @@ -231,23 +222,52 @@ fn check_expr(cx: &mut MatchCheckCtxt, ex: &hir::Expr) { .iter() .filter(|&&(_, guard)| guard.is_none()) .flat_map(|arm| &arm.0) - .map(|pat| vec![wrap_pat(cx, &pat)]) + .map(|pat| vec![pat.0]) .collect(); check_exhaustive(cx, scrut.span, &matrix, source); - }, - _ => () + }) + } + + fn check_irrefutable(&self, pat: &Pat, is_fn_arg: bool) { + let origin = if is_fn_arg { + "function argument" + } else { + "local binding" + }; + + MatchCheckCtxt::create_and_enter(self.tcx, |ref mut cx| { + let mut patcx = PatternContext::new(self.tcx); + let pats : Matrix = vec![vec![ + expand_pattern(cx, patcx.lower_pattern(pat)) + ]].into_iter().collect(); + + let witness = match is_useful(cx, &pats, &[cx.wild_pattern], ConstructWitness) { + UsefulWithWitness(witness) => witness, + NotUseful => return, + Useful => bug!() + }; + + let pattern_string = pat_to_string(witness[0].single_pattern()); + let mut diag = struct_span_err!( + self.tcx.sess, pat.span, E0005, + "refutable pattern in {}: `{}` not covered", + origin, pattern_string + ); + diag.span_label(pat.span, &format!("pattern `{}` not covered", pattern_string)); + diag.emit(); + }); } } -fn check_for_bindings_named_the_same_as_variants(cx: &MatchCheckCtxt, pat: &Pat) { +fn check_for_bindings_named_the_same_as_variants(cx: &MatchVisitor, pat: &Pat) { pat.walk(|p| { if let PatKind::Binding(hir::BindByValue(hir::MutImmutable), name, None) = p.node { - let pat_ty = cx.tcx.pat_ty(p); + let pat_ty = cx.tcx.tables().pat_ty(p); if let ty::TyAdt(edef, _) = pat_ty.sty { if edef.is_enum() { if let Def::Local(..) = cx.tcx.expect_def(p.id) { if edef.variants.iter().any(|variant| { - variant.name == name.node && variant.kind == ty::VariantKind::Unit + variant.name == name.node && variant.ctor_kind == CtorKind::Const }) { let ty_path = cx.tcx.item_path_str(edef.did); let mut err = struct_span_warn!(cx.tcx.sess, p.span, E0170, @@ -268,36 +288,30 @@ fn check_for_bindings_named_the_same_as_variants(cx: &MatchCheckCtxt, pat: &Pat) }); } -// Check that we do not match against a static NaN (#6804) -fn check_for_static_nan(cx: &MatchCheckCtxt, pat: &Pat) { - pat.walk(|p| { - if let PatKind::Lit(ref expr) = p.node { - match eval_const_expr_partial(cx.tcx, &expr, ExprTypeChecked, None) { - Ok(ConstVal::Float(f)) if f.is_nan() => { - span_warn!(cx.tcx.sess, p.span, E0003, - "unmatchable NaN in pattern, \ - use the is_nan method in a guard instead"); - } - Ok(_) => {} - - Err(err) => { - report_const_eval_err(cx.tcx, &err, p.span, "pattern").emit(); - } - } - } - true - }); +/// Checks for common cases of "catchall" patterns that may not be intended as such. +fn pat_is_catchall(dm: &DefMap, pat: &Pat) -> bool { + match pat.node { + PatKind::Binding(.., None) => true, + PatKind::Binding(.., Some(ref s)) => pat_is_catchall(dm, s), + PatKind::Ref(ref s, _) => pat_is_catchall(dm, s), + PatKind::Tuple(ref v, _) => v.iter().all(|p| { + pat_is_catchall(dm, &p) + }), + _ => false + } } // Check for unreachable patterns -fn check_arms(cx: &MatchCheckCtxt, - arms: &[(Vec>, Option<&hir::Expr>)], - source: hir::MatchSource) { - let mut seen = Matrix(vec![]); +fn check_arms<'a, 'tcx>(cx: &mut MatchCheckCtxt<'a, 'tcx>, + arms: &[(Vec<(&'a Pattern<'tcx>, &hir::Pat)>, Option<&hir::Expr>)], + source: hir::MatchSource) +{ + let mut seen = Matrix::empty(); + let mut catchall = None; let mut printed_if_let_err = false; for &(ref pats, guard) in arms { - for pat in pats { - let v = vec![wrap_pat(cx, &pat)]; + for &(pat, hir_pat) in pats { + let v = vec![pat]; match is_useful(cx, &seen, &v[..], LeaveOutWitness) { NotUseful => { @@ -310,7 +324,7 @@ fn check_arms(cx: &MatchCheckCtxt, // find the first arm pattern so we can use its span let &(ref first_arm_pats, _) = &arms[0]; let first_pat = &first_arm_pats[0]; - let span = first_pat.span; + let span = first_pat.0.span; struct_span_err!(cx.tcx.sess, span, E0162, "irrefutable if-let pattern") .span_label(span, &format!("irrefutable pattern")) @@ -323,7 +337,7 @@ fn check_arms(cx: &MatchCheckCtxt, // find the first arm pattern so we can use its span let &(ref first_arm_pats, _) = &arms[0]; let first_pat = &first_arm_pats[0]; - let span = first_pat.span; + let span = first_pat.0.span; struct_span_err!(cx.tcx.sess, span, E0165, "irrefutable while-let pattern") .span_label(span, &format!("irrefutable pattern")) @@ -341,13 +355,10 @@ fn check_arms(cx: &MatchCheckCtxt, hir::MatchSource::Normal => { let mut err = struct_span_err!(cx.tcx.sess, pat.span, E0001, "unreachable pattern"); - err.span_label(pat.span, &format!("this is an unreachable pattern")); + err.span_label(pat.span, &"this is an unreachable pattern"); // if we had a catchall pattern, hint at that - for row in &seen.0 { - if pat_is_catchall(&cx.tcx.def_map.borrow(), row[0].0) { - span_note!(err, row[0].0.span, - "this pattern matches any value"); - } + if let Some(catchall) = catchall { + err.span_note(catchall, "this pattern matches any value"); } err.emit(); }, @@ -361,42 +372,25 @@ fn check_arms(cx: &MatchCheckCtxt, UsefulWithWitness(_) => bug!() } if guard.is_none() { - let Matrix(mut rows) = seen; - rows.push(v); - seen = Matrix(rows); + seen.push(v); + if catchall.is_none() && pat_is_catchall(&cx.tcx.def_map.borrow(), hir_pat) { + catchall = Some(pat.span); + } } } } } -/// Checks for common cases of "catchall" patterns that may not be intended as such. -fn pat_is_catchall(dm: &DefMap, p: &Pat) -> bool { - match p.node { - PatKind::Binding(.., None) => true, - PatKind::Binding(.., Some(ref s)) => pat_is_catchall(dm, &s), - PatKind::Ref(ref s, _) => pat_is_catchall(dm, &s), - PatKind::Tuple(ref v, _) => v.iter().all(|p| pat_is_catchall(dm, &p)), - _ => false - } -} - -fn raw_pat(p: &Pat) -> &Pat { - match p.node { - PatKind::Binding(.., Some(ref s)) => raw_pat(&s), - _ => p - } -} - -fn check_exhaustive<'a, 'tcx>(cx: &MatchCheckCtxt<'a, 'tcx>, +fn check_exhaustive<'a, 'tcx>(cx: &mut MatchCheckCtxt<'a, 'tcx>, sp: Span, matrix: &Matrix<'a, 'tcx>, source: hir::MatchSource) { - match is_useful(cx, matrix, &[(DUMMY_WILD_PAT, None)], ConstructWitness) { + match is_useful(cx, matrix, &[cx.wild_pattern], ConstructWitness) { UsefulWithWitness(pats) => { let witnesses = if pats.is_empty() { vec![DUMMY_WILD_PAT] } else { - pats.iter().map(|w| &**w).collect() + pats.iter().map(|w| w.single_pattern()).collect() }; match source { hir::MatchSource::ForLoopDesugar => { @@ -438,10 +432,11 @@ fn check_exhaustive<'a, 'tcx>(cx: &MatchCheckCtxt<'a, 'tcx>, 1 => format!("pattern {} not covered", joined_patterns), _ => format!("patterns {} not covered", joined_patterns) }; - struct_span_err!(cx.tcx.sess, sp, E0004, - "non-exhaustive patterns: {} not covered", - joined_patterns - ).span_label(sp, &label_text).emit(); + create_e0004(cx.tcx.sess, sp, + format!("non-exhaustive patterns: {} not covered", + joined_patterns)) + .span_label(sp, &label_text) + .emit(); }, } } @@ -452,663 +447,8 @@ fn check_exhaustive<'a, 'tcx>(cx: &MatchCheckCtxt<'a, 'tcx>, } } -fn const_val_to_expr(value: &ConstVal) -> P { - let node = match value { - &ConstVal::Bool(b) => ast::LitKind::Bool(b), - _ => bug!() - }; - P(hir::Expr { - id: DUMMY_NODE_ID, - node: hir::ExprLit(P(Spanned { node: node, span: DUMMY_SP })), - span: DUMMY_SP, - attrs: ast::ThinVec::new(), - }) -} - -struct StaticInliner<'a, 'tcx: 'a> { - tcx: TyCtxt<'a, 'tcx, 'tcx>, - failed: bool -} - -impl<'a, 'tcx> StaticInliner<'a, 'tcx> { - pub fn new<'b>(tcx: TyCtxt<'b, 'tcx, 'tcx>) -> StaticInliner<'b, 'tcx> { - StaticInliner { - tcx: tcx, - failed: false - } - } -} - -impl<'a, 'tcx> StaticInliner<'a, 'tcx> { - fn fold_pat(&mut self, pat: P) -> P { - match pat.node { - PatKind::Path(..) => { - match self.tcx.expect_def(pat.id) { - Def::AssociatedConst(did) | Def::Const(did) => { - let substs = Some(self.tcx.node_id_item_substs(pat.id).substs); - if let Some((const_expr, _)) = lookup_const_by_id(self.tcx, did, substs) { - match const_expr_to_pat(self.tcx, const_expr, pat.id, pat.span) { - Ok(new_pat) => return new_pat, - Err(def_id) => { - self.failed = true; - self.tcx.sess.span_err( - pat.span, - &format!("constants of the type `{}` \ - cannot be used in patterns", - self.tcx.item_path_str(def_id))); - } - } - } else { - self.failed = true; - span_err!(self.tcx.sess, pat.span, E0158, - "statics cannot be referenced in patterns"); - } - } - _ => {} - } - } - _ => {} - } - - pat.map(|Pat { id, node, span }| { - let node = match node { - PatKind::Binding(binding_mode, pth1, sub) => { - PatKind::Binding(binding_mode, pth1, sub.map(|x| self.fold_pat(x))) - } - PatKind::TupleStruct(pth, pats, ddpos) => { - PatKind::TupleStruct(pth, pats.move_map(|x| self.fold_pat(x)), ddpos) - } - PatKind::Struct(pth, fields, etc) => { - let fs = fields.move_map(|f| { - Spanned { - span: f.span, - node: hir::FieldPat { - name: f.node.name, - pat: self.fold_pat(f.node.pat), - is_shorthand: f.node.is_shorthand, - }, - } - }); - PatKind::Struct(pth, fs, etc) - } - PatKind::Tuple(elts, ddpos) => { - PatKind::Tuple(elts.move_map(|x| self.fold_pat(x)), ddpos) - } - PatKind::Box(inner) => PatKind::Box(self.fold_pat(inner)), - PatKind::Ref(inner, mutbl) => PatKind::Ref(self.fold_pat(inner), mutbl), - PatKind::Vec(before, slice, after) => { - PatKind::Vec(before.move_map(|x| self.fold_pat(x)), - slice.map(|x| self.fold_pat(x)), - after.move_map(|x| self.fold_pat(x))) - } - PatKind::Wild | - PatKind::Lit(_) | - PatKind::Range(..) | - PatKind::Path(..) => node - }; - Pat { - id: id, - node: node, - span: span - } - }) - } -} - -/// Constructs a partial witness for a pattern given a list of -/// patterns expanded by the specialization step. -/// -/// When a pattern P is discovered to be useful, this function is used bottom-up -/// to reconstruct a complete witness, e.g. a pattern P' that covers a subset -/// of values, V, where each value in that set is not covered by any previously -/// used patterns and is covered by the pattern P'. Examples: -/// -/// left_ty: tuple of 3 elements -/// pats: [10, 20, _] => (10, 20, _) -/// -/// left_ty: struct X { a: (bool, &'static str), b: usize} -/// pats: [(false, "foo"), 42] => X { a: (false, "foo"), b: 42 } -fn construct_witness<'a,'tcx>(cx: &MatchCheckCtxt<'a,'tcx>, ctor: &Constructor, - pats: Vec<&Pat>, left_ty: Ty<'tcx>) -> P { - let pats_len = pats.len(); - let mut pats = pats.into_iter().map(|p| P((*p).clone())); - let pat = match left_ty.sty { - ty::TyTuple(..) => PatKind::Tuple(pats.collect(), None), - - ty::TyAdt(adt, _) => { - let v = ctor.variant_for_adt(adt); - match v.kind { - ty::VariantKind::Struct => { - let field_pats: hir::HirVec<_> = v.fields.iter() - .zip(pats) - .filter(|&(_, ref pat)| pat.node != PatKind::Wild) - .map(|(field, pat)| Spanned { - span: DUMMY_SP, - node: hir::FieldPat { - name: field.name, - pat: pat, - is_shorthand: false, - } - }).collect(); - let has_more_fields = field_pats.len() < pats_len; - PatKind::Struct(def_to_path(cx.tcx, v.did), field_pats, has_more_fields) - } - ty::VariantKind::Tuple => { - PatKind::TupleStruct(def_to_path(cx.tcx, v.did), pats.collect(), None) - } - ty::VariantKind::Unit => { - PatKind::Path(None, def_to_path(cx.tcx, v.did)) - } - } - } - - ty::TyRef(_, ty::TypeAndMut { mutbl, .. }) => { - assert_eq!(pats_len, 1); - PatKind::Ref(pats.nth(0).unwrap(), mutbl) - } - - ty::TySlice(_) => match ctor { - &Slice(n) => { - assert_eq!(pats_len, n); - PatKind::Vec(pats.collect(), None, hir::HirVec::new()) - }, - _ => unreachable!() - }, - - ty::TyArray(_, len) => { - assert_eq!(pats_len, len); - PatKind::Vec(pats.collect(), None, hir::HirVec::new()) - } - - _ => { - match *ctor { - ConstantValue(ref v) => PatKind::Lit(const_val_to_expr(v)), - _ => PatKind::Wild, - } - } - }; - - P(hir::Pat { - id: DUMMY_NODE_ID, - node: pat, - span: DUMMY_SP - }) -} - -impl Constructor { - fn variant_for_adt<'tcx, 'container, 'a>(&self, - adt: &'a ty::AdtDefData<'tcx, 'container>) - -> &'a ty::VariantDefData<'tcx, 'container> { - match self { - &Variant(vid) => adt.variant_with_id(vid), - _ => adt.struct_variant() - } - } -} - -fn missing_constructors(cx: &MatchCheckCtxt, &Matrix(ref rows): &Matrix, - left_ty: Ty, max_slice_length: usize) -> Vec { - let used_constructors: Vec = rows.iter() - .flat_map(|row| pat_constructors(cx, row[0].0, left_ty, max_slice_length)) - .collect(); - all_constructors(cx, left_ty, max_slice_length) - .into_iter() - .filter(|c| !used_constructors.contains(c)) - .collect() -} - -/// This determines the set of all possible constructors of a pattern matching -/// values of type `left_ty`. For vectors, this would normally be an infinite set -/// but is instead bounded by the maximum fixed length of slice patterns in -/// the column of patterns being analyzed. -fn all_constructors(_cx: &MatchCheckCtxt, left_ty: Ty, - max_slice_length: usize) -> Vec { - match left_ty.sty { - ty::TyBool => - [true, false].iter().map(|b| ConstantValue(ConstVal::Bool(*b))).collect(), - ty::TySlice(_) => - (0..max_slice_length+1).map(|length| Slice(length)).collect(), - ty::TyAdt(def, _) if def.is_enum() => - def.variants.iter().map(|v| Variant(v.did)).collect(), - _ => vec![Single] - } -} - -// Algorithm from http://moscova.inria.fr/~maranget/papers/warn/index.html -// -// Whether a vector `v` of patterns is 'useful' in relation to a set of such -// vectors `m` is defined as there being a set of inputs that will match `v` -// but not any of the sets in `m`. -// -// This is used both for reachability checking (if a pattern isn't useful in -// relation to preceding patterns, it is not reachable) and exhaustiveness -// checking (if a wildcard pattern is useful in relation to a matrix, the -// matrix isn't exhaustive). - -// Note: is_useful doesn't work on empty types, as the paper notes. -// So it assumes that v is non-empty. -fn is_useful<'a, 'tcx>(cx: &MatchCheckCtxt<'a, 'tcx>, - matrix: &Matrix<'a, 'tcx>, - v: &[(&Pat, Option>)], - witness: WitnessPreference) - -> Usefulness { - let &Matrix(ref rows) = matrix; - debug!("is_useful({:?}, {:?})", matrix, v); - if rows.is_empty() { - return match witness { - ConstructWitness => UsefulWithWitness(vec!()), - LeaveOutWitness => Useful - }; - } - if rows[0].is_empty() { - return NotUseful; - } - assert!(rows.iter().all(|r| r.len() == v.len())); - let left_ty = match rows.iter().filter_map(|r| r[0].1).next().or_else(|| v[0].1) { - Some(ty) => ty, - None => { - // all patterns are wildcards - we can pick any type we want - cx.tcx.types.bool - } - }; - - let max_slice_length = rows.iter().filter_map(|row| match row[0].0.node { - PatKind::Vec(ref before, _, ref after) => Some(before.len() + after.len()), - _ => None - }).max().map_or(0, |v| v + 1); - - let constructors = pat_constructors(cx, v[0].0, left_ty, max_slice_length); - debug!("is_useful - pat_constructors = {:?} left_ty = {:?}", constructors, - left_ty); - if constructors.is_empty() { - let constructors = missing_constructors(cx, matrix, left_ty, max_slice_length); - debug!("is_useful - missing_constructors = {:?}", constructors); - if constructors.is_empty() { - all_constructors(cx, left_ty, max_slice_length).into_iter().map(|c| { - match is_useful_specialized(cx, matrix, v, c.clone(), left_ty, witness) { - UsefulWithWitness(pats) => UsefulWithWitness({ - let arity = constructor_arity(cx, &c, left_ty); - let mut result = { - let pat_slice = &pats[..]; - let subpats: Vec<_> = (0..arity).map(|i| { - pat_slice.get(i).map_or(DUMMY_WILD_PAT, |p| &**p) - }).collect(); - vec![construct_witness(cx, &c, subpats, left_ty)] - }; - result.extend(pats.into_iter().skip(arity)); - result - }), - result => result - } - }).find(|result| result != &NotUseful).unwrap_or(NotUseful) - } else { - let matrix = rows.iter().filter_map(|r| { - match raw_pat(r[0].0).node { - PatKind::Binding(..) | PatKind::Wild => Some(r[1..].to_vec()), - _ => None, - } - }).collect(); - match is_useful(cx, &matrix, &v[1..], witness) { - UsefulWithWitness(pats) => { - let mut new_pats: Vec<_> = constructors.into_iter().map(|constructor| { - let arity = constructor_arity(cx, &constructor, left_ty); - let wild_pats = vec![DUMMY_WILD_PAT; arity]; - construct_witness(cx, &constructor, wild_pats, left_ty) - }).collect(); - new_pats.extend(pats); - UsefulWithWitness(new_pats) - }, - result => result - } - } - } else { - constructors.into_iter().map(|c| - is_useful_specialized(cx, matrix, v, c.clone(), left_ty, witness) - ).find(|result| result != &NotUseful).unwrap_or(NotUseful) - } -} - -fn is_useful_specialized<'a, 'tcx>( - cx: &MatchCheckCtxt<'a, 'tcx>, - &Matrix(ref m): &Matrix<'a, 'tcx>, - v: &[(&Pat, Option>)], - ctor: Constructor, - lty: Ty<'tcx>, - witness: WitnessPreference) -> Usefulness -{ - let arity = constructor_arity(cx, &ctor, lty); - let matrix = Matrix(m.iter().filter_map(|r| { - specialize(cx, &r[..], &ctor, 0, arity) - }).collect()); - match specialize(cx, v, &ctor, 0, arity) { - Some(v) => is_useful(cx, &matrix, &v[..], witness), - None => NotUseful - } -} - -/// Determines the constructors that the given pattern can be specialized to. -/// -/// In most cases, there's only one constructor that a specific pattern -/// represents, such as a specific enum variant or a specific literal value. -/// Slice patterns, however, can match slices of different lengths. For instance, -/// `[a, b, ..tail]` can match a slice of length 2, 3, 4 and so on. -/// -/// On the other hand, a wild pattern and an identifier pattern cannot be -/// specialized in any way. -fn pat_constructors(cx: &MatchCheckCtxt, p: &Pat, - left_ty: Ty, max_slice_length: usize) -> Vec { - let pat = raw_pat(p); - match pat.node { - PatKind::Struct(..) | PatKind::TupleStruct(..) | PatKind::Path(..) => - match cx.tcx.expect_def(pat.id) { - Def::Variant(id) => vec![Variant(id)], - Def::Struct(..) | Def::Union(..) | - Def::TyAlias(..) | Def::AssociatedTy(..) => vec![Single], - Def::Const(..) | Def::AssociatedConst(..) => - span_bug!(pat.span, "const pattern should've been rewritten"), - def => span_bug!(pat.span, "pat_constructors: unexpected definition {:?}", def), - }, - PatKind::Lit(ref expr) => - vec![ConstantValue(eval_const_expr(cx.tcx, &expr))], - PatKind::Range(ref lo, ref hi) => - vec![ConstantRange(eval_const_expr(cx.tcx, &lo), eval_const_expr(cx.tcx, &hi))], - PatKind::Vec(ref before, ref slice, ref after) => - match left_ty.sty { - ty::TyArray(..) => vec![Single], - ty::TySlice(_) if slice.is_some() => { - (before.len() + after.len()..max_slice_length+1) - .map(|length| Slice(length)) - .collect() - } - ty::TySlice(_) => vec!(Slice(before.len() + after.len())), - _ => span_bug!(pat.span, "pat_constructors: unexpected \ - slice pattern type {:?}", left_ty) - }, - PatKind::Box(..) | PatKind::Tuple(..) | PatKind::Ref(..) => - vec![Single], - PatKind::Binding(..) | PatKind::Wild => - vec![], - } -} - -/// This computes the arity of a constructor. The arity of a constructor -/// is how many subpattern patterns of that constructor should be expanded to. -/// -/// For instance, a tuple pattern (_, 42, Some([])) has the arity of 3. -/// A struct pattern's arity is the number of fields it contains, etc. -pub fn constructor_arity(_cx: &MatchCheckCtxt, ctor: &Constructor, ty: Ty) -> usize { - debug!("constructor_arity({:?}, {:?})", ctor, ty); - match ty.sty { - ty::TyTuple(ref fs) => fs.len(), - ty::TyBox(_) => 1, - ty::TySlice(_) => match *ctor { - Slice(length) => length, - ConstantValue(_) => 0, - _ => bug!() - }, - ty::TyRef(..) => 1, - ty::TyAdt(adt, _) => { - ctor.variant_for_adt(adt).fields.len() - } - ty::TyArray(_, n) => n, - _ => 0 - } -} - -fn range_covered_by_constructor(tcx: TyCtxt, span: Span, - ctor: &Constructor, - from: &ConstVal, to: &ConstVal) - -> Result { - let (c_from, c_to) = match *ctor { - ConstantValue(ref value) => (value, value), - ConstantRange(ref from, ref to) => (from, to), - Single => return Ok(true), - _ => bug!() - }; - let cmp_from = compare_const_vals(tcx, span, c_from, from)?; - let cmp_to = compare_const_vals(tcx, span, c_to, to)?; - Ok(cmp_from != Ordering::Less && cmp_to != Ordering::Greater) -} - -fn wrap_pat<'a, 'b, 'tcx>(cx: &MatchCheckCtxt<'b, 'tcx>, - pat: &'a Pat) - -> (&'a Pat, Option>) -{ - let pat_ty = cx.tcx.pat_ty(pat); - (pat, Some(match pat.node { - PatKind::Binding(hir::BindByRef(..), ..) => { - pat_ty.builtin_deref(false, ty::NoPreference).unwrap().ty - } - _ => pat_ty - })) -} - -/// This is the main specialization step. It expands the first pattern in the given row -/// into `arity` patterns based on the constructor. For most patterns, the step is trivial, -/// for instance tuple patterns are flattened and box patterns expand into their inner pattern. -/// -/// OTOH, slice patterns with a subslice pattern (..tail) can be expanded into multiple -/// different patterns. -/// Structure patterns with a partial wild pattern (Foo { a: 42, .. }) have their missing -/// fields filled with wild patterns. -pub fn specialize<'a, 'b, 'tcx>( - cx: &MatchCheckCtxt<'b, 'tcx>, - r: &[(&'a Pat, Option>)], - constructor: &Constructor, col: usize, arity: usize) - -> Option>)>> -{ - let pat = raw_pat(r[col].0); - let &Pat { - id: pat_id, ref node, span: pat_span - } = pat; - let wpat = |pat: &'a Pat| wrap_pat(cx, pat); - let dummy_pat = (DUMMY_WILD_PAT, None); - - let head: Option)>> = match *node { - PatKind::Binding(..) | PatKind::Wild => - Some(vec![dummy_pat; arity]), - - PatKind::Path(..) => { - match cx.tcx.expect_def(pat_id) { - Def::Const(..) | Def::AssociatedConst(..) => - span_bug!(pat_span, "const pattern should've \ - been rewritten"), - Def::Variant(id) if *constructor != Variant(id) => None, - Def::Variant(..) | Def::Struct(..) => Some(Vec::new()), - def => span_bug!(pat_span, "specialize: unexpected \ - definition {:?}", def), - } - } - - PatKind::TupleStruct(_, ref args, ddpos) => { - match cx.tcx.expect_def(pat_id) { - Def::Const(..) | Def::AssociatedConst(..) => - span_bug!(pat_span, "const pattern should've \ - been rewritten"), - Def::Variant(id) if *constructor != Variant(id) => None, - Def::Variant(..) | Def::Struct(..) => { - match ddpos { - Some(ddpos) => { - let mut pats: Vec<_> = args[..ddpos].iter().map(|p| { - wpat(p) - }).collect(); - pats.extend(repeat((DUMMY_WILD_PAT, None)).take(arity - args.len())); - pats.extend(args[ddpos..].iter().map(|p| wpat(p))); - Some(pats) - } - None => Some(args.iter().map(|p| wpat(p)).collect()) - } - } - _ => None - } - } - - PatKind::Struct(_, ref pattern_fields, _) => { - let adt = cx.tcx.node_id_to_type(pat_id).ty_adt_def().unwrap(); - let variant = constructor.variant_for_adt(adt); - let def_variant = adt.variant_of_def(cx.tcx.expect_def(pat_id)); - if variant.did == def_variant.did { - Some(variant.fields.iter().map(|sf| { - match pattern_fields.iter().find(|f| f.node.name == sf.name) { - Some(ref f) => wpat(&f.node.pat), - _ => dummy_pat - } - }).collect()) - } else { - None - } - } - - PatKind::Tuple(ref args, Some(ddpos)) => { - let mut pats: Vec<_> = args[..ddpos].iter().map(|p| wpat(p)).collect(); - pats.extend(repeat(dummy_pat).take(arity - args.len())); - pats.extend(args[ddpos..].iter().map(|p| wpat(p))); - Some(pats) - } - PatKind::Tuple(ref args, None) => - Some(args.iter().map(|p| wpat(&**p)).collect()), - - PatKind::Box(ref inner) | PatKind::Ref(ref inner, _) => - Some(vec![wpat(&**inner)]), - - PatKind::Lit(ref expr) => { - if let Some(&ty::TyS { sty: ty::TyRef(_, mt), .. }) = r[col].1 { - // HACK: handle string literals. A string literal pattern - // serves both as an unary reference pattern and as a - // nullary value pattern, depending on the type. - Some(vec![(pat, Some(mt.ty))]) - } else { - let expr_value = eval_const_expr(cx.tcx, &expr); - match range_covered_by_constructor( - cx.tcx, expr.span, constructor, &expr_value, &expr_value - ) { - Ok(true) => Some(vec![]), - Ok(false) => None, - Err(ErrorReported) => None, - } - } - } - - PatKind::Range(ref from, ref to) => { - let from_value = eval_const_expr(cx.tcx, &from); - let to_value = eval_const_expr(cx.tcx, &to); - match range_covered_by_constructor( - cx.tcx, pat_span, constructor, &from_value, &to_value - ) { - Ok(true) => Some(vec![]), - Ok(false) => None, - Err(ErrorReported) => None, - } - } - - PatKind::Vec(ref before, ref slice, ref after) => { - let pat_len = before.len() + after.len(); - match *constructor { - Single => { - // Fixed-length vectors. - Some( - before.iter().map(|p| wpat(p)).chain( - repeat(dummy_pat).take(arity - pat_len).chain( - after.iter().map(|p| wpat(p)) - )).collect()) - }, - Slice(length) if pat_len <= length && slice.is_some() => { - Some( - before.iter().map(|p| wpat(p)).chain( - repeat(dummy_pat).take(arity - pat_len).chain( - after.iter().map(|p| wpat(p)) - )).collect()) - } - Slice(length) if pat_len == length => { - Some( - before.iter().map(|p| wpat(p)).chain( - after.iter().map(|p| wpat(p)) - ).collect()) - } - SliceWithSubslice(prefix, suffix) - if before.len() == prefix - && after.len() == suffix - && slice.is_some() => { - // this is used by trans::_match only - let mut pats: Vec<_> = before.iter() - .map(|p| (&**p, None)).collect(); - pats.extend(after.iter().map(|p| (&**p, None))); - Some(pats) - } - _ => None - } - } - }; - debug!("specialize({:?}, {:?}) = {:?}", r[col], arity, head); - - head.map(|mut head| { - head.extend_from_slice(&r[..col]); - head.extend_from_slice(&r[col + 1..]); - head - }) -} - -fn check_local(cx: &mut MatchCheckCtxt, loc: &hir::Local) { - intravisit::walk_local(cx, loc); - - let pat = StaticInliner::new(cx.tcx).fold_pat(loc.pat.clone()); - check_irrefutable(cx, &pat, false); - - // Check legality of move bindings and `@` patterns. - check_legality_of_move_bindings(cx, false, slice::ref_slice(&loc.pat)); - check_legality_of_bindings_in_at_patterns(cx, &loc.pat); -} - -fn check_fn(cx: &mut MatchCheckCtxt, - kind: FnKind, - decl: &hir::FnDecl, - body: &hir::Block, - sp: Span, - fn_id: NodeId) { - match kind { - FnKind::Closure(_) => {} - _ => cx.param_env = ty::ParameterEnvironment::for_item(cx.tcx, fn_id), - } - - intravisit::walk_fn(cx, kind, decl, body, sp, fn_id); - - for input in &decl.inputs { - check_irrefutable(cx, &input.pat, true); - check_legality_of_move_bindings(cx, false, slice::ref_slice(&input.pat)); - check_legality_of_bindings_in_at_patterns(cx, &input.pat); - } -} - -fn check_irrefutable(cx: &MatchCheckCtxt, pat: &Pat, is_fn_arg: bool) { - let origin = if is_fn_arg { - "function argument" - } else { - "local binding" - }; - - is_refutable(cx, pat, |uncovered_pat| { - let pattern_string = pat_to_string(uncovered_pat); - struct_span_err!(cx.tcx.sess, pat.span, E0005, - "refutable pattern in {}: `{}` not covered", - origin, - pattern_string, - ).span_label(pat.span, &format!("pattern `{}` not covered", pattern_string)).emit(); - }); -} - -fn is_refutable(cx: &MatchCheckCtxt, pat: &Pat, refutable: F) -> Option where - F: FnOnce(&Pat) -> A, -{ - let pats = Matrix(vec!(vec!(wrap_pat(cx, pat)))); - match is_useful(cx, &pats, &[(DUMMY_WILD_PAT, None)], ConstructWitness) { - UsefulWithWitness(pats) => Some(refutable(&pats[0])), - NotUseful => None, - Useful => bug!() - } -} - // Legality of move bindings checking -fn check_legality_of_move_bindings(cx: &MatchCheckCtxt, +fn check_legality_of_move_bindings(cx: &MatchVisitor, has_guard: bool, pats: &[P]) { let mut by_ref_span = None; @@ -1146,14 +486,10 @@ fn check_legality_of_move_bindings(cx: &MatchCheckCtxt, for pat in pats { pat.walk(|p| { if let PatKind::Binding(hir::BindByValue(..), _, ref sub) = p.node { - let pat_ty = cx.tcx.node_id_to_type(p.id); - //FIXME: (@jroesch) this code should be floated up as well - cx.tcx.infer_ctxt(None, Some(cx.param_env.clone()), - Reveal::NotSpecializable).enter(|infcx| { - if infcx.type_moves_by_default(pat_ty, pat.span) { - check_move(p, sub.as_ref().map(|p| &**p)); - } - }); + let pat_ty = cx.tcx.tables().node_id_to_type(p.id); + if pat_ty.moves_by_default(cx.tcx, cx.param_env, pat.span) { + check_move(p, sub.as_ref().map(|p| &**p)); + } } true }); @@ -1162,8 +498,9 @@ fn check_legality_of_move_bindings(cx: &MatchCheckCtxt, /// Ensures that a pattern guard doesn't borrow by mutable reference or /// assign. -fn check_for_mutation_in_guard<'a, 'tcx>(cx: &'a MatchCheckCtxt<'a, 'tcx>, - guard: &hir::Expr) { +/// +/// FIXME: this should be done by borrowck. +fn check_for_mutation_in_guard(cx: &MatchVisitor, guard: &hir::Expr) { cx.tcx.infer_ctxt(None, Some(cx.param_env.clone()), Reveal::NotSpecializable).enter(|infcx| { let mut checker = MutationChecker { @@ -1175,15 +512,15 @@ fn check_for_mutation_in_guard<'a, 'tcx>(cx: &'a MatchCheckCtxt<'a, 'tcx>, } struct MutationChecker<'a, 'gcx: 'a> { - cx: &'a MatchCheckCtxt<'a, 'gcx>, + cx: &'a MatchVisitor<'a, 'gcx>, } impl<'a, 'gcx, 'tcx> Delegate<'tcx> for MutationChecker<'a, 'gcx> { fn matched_pat(&mut self, _: &Pat, _: cmt, _: euv::MatchMode) {} - fn consume(&mut self, _: NodeId, _: Span, _: cmt, _: ConsumeMode) {} + fn consume(&mut self, _: ast::NodeId, _: Span, _: cmt, _: ConsumeMode) {} fn consume_pat(&mut self, _: &Pat, _: cmt, _: ConsumeMode) {} fn borrow(&mut self, - _: NodeId, + _: ast::NodeId, span: Span, _: cmt, _: &'tcx ty::Region, @@ -1199,8 +536,8 @@ impl<'a, 'gcx, 'tcx> Delegate<'tcx> for MutationChecker<'a, 'gcx> { ty::ImmBorrow | ty::UniqueImmBorrow => {} } } - fn decl_without_init(&mut self, _: NodeId, _: Span) {} - fn mutate(&mut self, _: NodeId, span: Span, _: cmt, mode: MutateMode) { + fn decl_without_init(&mut self, _: ast::NodeId, _: Span) {} + fn mutate(&mut self, _: ast::NodeId, span: Span, _: cmt, mode: MutateMode) { match mode { MutateMode::JustWrite | MutateMode::WriteAndRead => { struct_span_err!(self.cx.tcx.sess, span, E0302, "cannot assign in a pattern guard") @@ -1215,12 +552,12 @@ impl<'a, 'gcx, 'tcx> Delegate<'tcx> for MutationChecker<'a, 'gcx> { /// Forbids bindings in `@` patterns. This is necessary for memory safety, /// because of the way rvalues are handled in the borrow check. (See issue /// #14587.) -fn check_legality_of_bindings_in_at_patterns(cx: &MatchCheckCtxt, pat: &Pat) { +fn check_legality_of_bindings_in_at_patterns(cx: &MatchVisitor, pat: &Pat) { AtBindingPatternVisitor { cx: cx, bindings_allowed: true }.visit_pat(pat); } struct AtBindingPatternVisitor<'a, 'b:'a, 'tcx:'b> { - cx: &'a MatchCheckCtxt<'b, 'tcx>, + cx: &'a MatchVisitor<'b, 'tcx>, bindings_allowed: bool } @@ -1229,8 +566,10 @@ impl<'a, 'b, 'tcx, 'v> Visitor<'v> for AtBindingPatternVisitor<'a, 'b, 'tcx> { match pat.node { PatKind::Binding(.., ref subpat) => { if !self.bindings_allowed { - span_err!(self.cx.tcx.sess, pat.span, E0303, - "pattern bindings are not allowed after an `@`"); + struct_span_err!(self.cx.tcx.sess, pat.span, E0303, + "pattern bindings are not allowed after an `@`") + .span_label(pat.span, &format!("not allowed after `@`")) + .emit(); } if subpat.is_some() { diff --git a/src/librustc_const_eval/diagnostics.rs b/src/librustc_const_eval/diagnostics.rs index 9cdc76f25a..db72057636 100644 --- a/src/librustc_const_eval/diagnostics.rs +++ b/src/librustc_const_eval/diagnostics.rs @@ -40,7 +40,7 @@ Ensure the ordering of the match arm is correct and remove any superfluous arms. "##, -E0002: r##" +/*E0002: r##" This error indicates that an empty match expression is invalid 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 @@ -68,16 +68,14 @@ fn foo(x: Option) { } } ``` -"##, +"##,*/ -E0003: r##" +/*E0003: r##" Not-a-Number (NaN) values cannot be compared for equality and hence can never match the input to a match expression. So, the following will not compile: ```compile_fail -#![deny(illegal_floating_point_constant_pattern)] - const NAN: f32 = 0.0 / 0.0; let number = 0.1f32; @@ -100,7 +98,7 @@ match number { } ``` "##, - +*/ E0004: r##" This error indicates that the compiler cannot guarantee a matching pattern for @@ -456,7 +454,7 @@ loop variable, consider using a `match` or `if let` inside the loop body. For instance: ```compile_fail,E0297 -let xs : Vec> = vec!(Some(1), None); +let xs : Vec> = vec![Some(1), None]; // This fails because `None` is not covered. for Some(x) in xs { @@ -467,7 +465,7 @@ for Some(x) in xs { Match inside the loop instead: ``` -let xs : Vec> = vec!(Some(1), None); +let xs : Vec> = vec![Some(1), None]; for item in xs { match item { @@ -480,7 +478,7 @@ for item in xs { Or use `if let`: ``` -let xs : Vec> = vec!(Some(1), None); +let xs : Vec> = vec![Some(1), None]; for item in xs { if let Some(x) = item { diff --git a/src/librustc_const_eval/eval.rs b/src/librustc_const_eval/eval.rs index 4ae3c7d37d..57a5400eca 100644 --- a/src/librustc_const_eval/eval.rs +++ b/src/librustc_const_eval/eval.rs @@ -19,7 +19,7 @@ use rustc::hir::map as ast_map; use rustc::hir::map::blocks::FnLikeNode; use rustc::middle::cstore::InlinedItem; use rustc::traits; -use rustc::hir::def::{Def, PathResolution}; +use rustc::hir::def::{Def, CtorKind, PathResolution}; use rustc::hir::def_id::DefId; use rustc::hir::pat_util::def_to_path; use rustc::ty::{self, Ty, TyCtxt}; @@ -27,7 +27,7 @@ use rustc::ty::util::IntTypeExt; use rustc::ty::subst::Substs; use rustc::traits::Reveal; use rustc::util::common::ErrorReported; -use rustc::util::nodemap::NodeMap; +use rustc::util::nodemap::DefIdMap; use rustc::lint; use graphviz::IntoCow; @@ -246,7 +246,7 @@ pub fn const_expr_to_pat<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, pat_id: ast::NodeId, span: Span) -> Result, DefId> { - let pat_ty = tcx.expr_ty(expr); + let pat_ty = tcx.tables().expr_ty(expr); debug!("expr={:?} pat_ty={:?} pat_id={}", expr, pat_ty, pat_id); match pat_ty.sty { ty::TyFloat(_) => { @@ -287,8 +287,8 @@ pub fn const_expr_to_pat<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, entry.insert(PathResolution::new(def)); } let path = match def { - Def::Struct(def_id) => def_to_path(tcx, def_id), - Def::Variant(variant_did) => def_to_path(tcx, variant_did), + Def::StructCtor(def_id, CtorKind::Fn) | + Def::VariantCtor(def_id, CtorKind::Fn) => def_to_path(tcx, def_id), Def::Fn(..) | Def::Method(..) => return Ok(P(hir::Pat { id: expr.id, node: PatKind::Lit(P(expr.clone())), @@ -314,21 +314,23 @@ pub fn const_expr_to_pat<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, }, })) .collect::>()?; - PatKind::Struct(path.clone(), field_pats, false) + PatKind::Struct((**path).clone(), field_pats, false) } - hir::ExprVec(ref exprs) => { + hir::ExprArray(ref exprs) => { let pats = exprs.iter() .map(|expr| const_expr_to_pat(tcx, &expr, pat_id, span)) .collect::>()?; - PatKind::Vec(pats, None, hir::HirVec::new()) + PatKind::Slice(pats, None, hir::HirVec::new()) } hir::ExprPath(_, ref path) => { match tcx.expect_def(expr.id) { - Def::Struct(..) | Def::Variant(..) => PatKind::Path(None, path.clone()), + Def::StructCtor(_, CtorKind::Const) | + Def::VariantCtor(_, CtorKind::Const) => PatKind::Path(None, path.clone()), Def::Const(def_id) | Def::AssociatedConst(def_id) => { - let substs = Some(tcx.node_id_item_substs(expr.id).substs); + let substs = Some(tcx.tables().node_id_item_substs(expr.id) + .unwrap_or_else(|| tcx.intern_substs(&[]))); let (expr, _ty) = lookup_const_by_id(tcx, def_id, substs).unwrap(); return const_expr_to_pat(tcx, expr, pat_id, span); }, @@ -391,7 +393,7 @@ pub fn note_const_eval_err<'a, 'tcx>( pub fn eval_const_expr<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, e: &Expr) -> ConstVal { - match eval_const_expr_partial(tcx, e, ExprTypeChecked, None) { + match eval_const_expr_checked(tcx, e) { Ok(r) => r, // non-const path still needs to be a fatal error, because enums are funky Err(s) => { @@ -406,15 +408,21 @@ pub fn eval_const_expr<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, } } -pub type FnArgMap<'a> = Option<&'a NodeMap>; +pub fn eval_const_expr_checked<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, + e: &Expr) -> EvalResult +{ + eval_const_expr_partial(tcx, e, ExprTypeChecked, None) +} + +pub type FnArgMap<'a> = Option<&'a DefIdMap>; -#[derive(Clone)] +#[derive(Clone, Debug)] pub struct ConstEvalErr { pub span: Span, pub kind: ErrKind, } -#[derive(Clone)] +#[derive(Clone, Debug)] pub enum ErrKind { CannotCast, CannotCastTo(&'static str), @@ -599,7 +607,7 @@ pub fn eval_const_expr_partial<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, let ety = match ty_hint { ExprTypeChecked => { // After type-checking, expr_ty is guaranteed to succeed. - Some(tcx.expr_ty(e)) + Some(tcx.tables().expr_ty(e)) } UncheckedExprHint(ty) => { // Use the type hint; it's not guaranteed to be right, but it's @@ -610,7 +618,7 @@ pub fn eval_const_expr_partial<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, // This expression might not be type-checked, and we have no hint. // Try to query the context for a type anyway; we might get lucky // (for example, if the expression was imported from another crate). - tcx.expr_ty_opt(e) + tcx.tables().expr_ty_opt(e) } }; let result = match e.node { @@ -731,6 +739,10 @@ pub fn eval_const_expr_partial<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, hir::BiBitOr => a | b, hir::BiEq => a == b, hir::BiNe => a != b, + hir::BiLt => a < b, + hir::BiLe => a <= b, + hir::BiGe => a >= b, + hir::BiGt => a > b, _ => signal!(e, InvalidOpForBools(op.node)), }) } @@ -748,7 +760,7 @@ pub fn eval_const_expr_partial<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, let base_hint = if let ExprTypeChecked = ty_hint { ExprTypeChecked } else { - match tcx.expr_ty_opt(&base) { + match tcx.tables().expr_ty_opt(&base) { Some(t) => UncheckedExprHint(t), None => ty_hint } @@ -787,7 +799,8 @@ pub fn eval_const_expr_partial<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, Def::Const(def_id) | Def::AssociatedConst(def_id) => { let substs = if let ExprTypeChecked = ty_hint { - Some(tcx.node_id_item_substs(e.id).substs) + Some(tcx.tables().node_id_item_substs(e.id) + .unwrap_or_else(|| tcx.intern_substs(&[]))) } else { None }; @@ -807,7 +820,7 @@ pub fn eval_const_expr_partial<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, signal!(e, NonConstPath); } }, - Def::Variant(variant_def) => { + Def::VariantCtor(variant_def, ..) => { if let Some(const_expr) = lookup_variant_by_id(tcx, variant_def) { match eval_const_expr_partial(tcx, const_expr, ty_hint, None) { Ok(val) => val, @@ -820,13 +833,12 @@ pub fn eval_const_expr_partial<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, signal!(e, UnimplementedConstVal("enum variants")); } } - Def::Struct(..) => { + Def::StructCtor(..) => { ConstVal::Struct(e.id) } Def::Local(def_id) => { - let id = tcx.map.as_local_node_id(def_id).unwrap(); - debug!("Def::Local({:?}): {:?}", id, fn_args); - if let Some(val) = fn_args.and_then(|args| args.get(&id)) { + debug!("Def::Local({:?}): {:?}", def_id, fn_args); + if let Some(val) = fn_args.and_then(|args| args.get(&def_id)) { val.clone() } else { signal!(e, NonConstPath); @@ -852,7 +864,7 @@ pub fn eval_const_expr_partial<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, let result = result.as_ref().expect("const fn has no result expression"); assert_eq!(decl.inputs.len(), args.len()); - let mut call_args = NodeMap(); + let mut call_args = DefIdMap(); for (arg, arg_expr) in decl.inputs.iter().zip(args.iter()) { let arg_hint = ty_hint.erase_hint(); let arg_val = eval_const_expr_partial( @@ -862,7 +874,7 @@ pub fn eval_const_expr_partial<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, fn_args )?; debug!("const call arg: {:?}", arg); - let old = call_args.insert(arg.pat.id, arg_val); + let old = call_args.insert(tcx.expect_def(arg.pat.id).def_id(), arg_val); assert!(old.is_none()); } debug!("const call({:?})", call_args); @@ -898,7 +910,7 @@ pub fn eval_const_expr_partial<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, Array(_, n) if idx >= n => { signal!(e, IndexOutOfBounds { len: n, index: idx }) } - Array(v, n) => if let hir::ExprVec(ref v) = tcx.map.expect_expr(v).node { + Array(v, n) => if let hir::ExprArray(ref v) = tcx.map.expect_expr(v).node { assert_eq!(n as usize as u64, n); eval_const_expr_partial(tcx, &v[idx as usize], ty_hint, fn_args)? } else { @@ -925,7 +937,7 @@ pub fn eval_const_expr_partial<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, _ => signal!(e, IndexedNonVec), } } - hir::ExprVec(ref v) => Array(e.id, v.len() as u64), + hir::ExprArray(ref v) => Array(e.id, v.len() as u64), hir::ExprRepeat(_, ref n) => { let len_hint = ty_hint.checked_or(tcx.types.usize); Repeat( diff --git a/src/librustc_const_eval/lib.rs b/src/librustc_const_eval/lib.rs index 7b40269ba5..3fa60f86c9 100644 --- a/src/librustc_const_eval/lib.rs +++ b/src/librustc_const_eval/lib.rs @@ -22,7 +22,7 @@ html_favicon_url = "https://doc.rust-lang.org/favicon.ico", html_root_url = "https://doc.rust-lang.org/nightly/")] -#![feature(dotdot_in_tuple_patterns)] +#![cfg_attr(stage0, feature(dotdot_in_tuple_patterns))] #![feature(rustc_private)] #![feature(staged_api)] #![feature(rustc_diagnostic_macros)] @@ -31,11 +31,13 @@ #![feature(box_patterns)] #![feature(box_syntax)] +extern crate arena; #[macro_use] extern crate syntax; #[macro_use] extern crate log; #[macro_use] extern crate rustc; extern crate rustc_back; extern crate rustc_const_math; +extern crate rustc_data_structures; extern crate rustc_errors; extern crate graphviz; extern crate syntax_pos; @@ -46,7 +48,9 @@ extern crate serialize as rustc_serialize; // used by deriving pub mod diagnostics; mod eval; +mod _match; pub mod check_match; +pub mod pattern; pub use eval::*; diff --git a/src/librustc_const_eval/pattern.rs b/src/librustc_const_eval/pattern.rs new file mode 100644 index 0000000000..241920f294 --- /dev/null +++ b/src/librustc_const_eval/pattern.rs @@ -0,0 +1,614 @@ +// Copyright 2016 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +use eval; + +use rustc::middle::const_val::ConstVal; +use rustc::mir::{Field, BorrowKind, Mutability}; +use rustc::ty::{self, TyCtxt, AdtDef, Ty, Region}; +use rustc::hir::{self, PatKind}; +use rustc::hir::def::Def; +use rustc::hir::def_id::DefId; +use rustc::hir::pat_util::EnumerateAndAdjustIterator; + +use rustc_data_structures::indexed_vec::Idx; + +use syntax::ast; +use syntax::ptr::P; +use syntax_pos::Span; + +#[derive(Clone, Debug)] +pub enum PatternError { + StaticInPattern(Span), + BadConstInPattern(Span, DefId), + ConstEval(eval::ConstEvalErr), +} + +#[derive(Copy, Clone, Debug)] +pub enum BindingMode<'tcx> { + ByValue, + ByRef(&'tcx Region, BorrowKind), +} + +#[derive(Clone, Debug)] +pub struct FieldPattern<'tcx> { + pub field: Field, + pub pattern: Pattern<'tcx>, +} + +#[derive(Clone, Debug)] +pub struct Pattern<'tcx> { + pub ty: Ty<'tcx>, + pub span: Span, + pub kind: Box>, +} + +#[derive(Clone, Debug)] +pub enum PatternKind<'tcx> { + Wild, + + /// x, ref x, x @ P, etc + Binding { + mutability: Mutability, + name: ast::Name, + mode: BindingMode<'tcx>, + var: ast::NodeId, + ty: Ty<'tcx>, + subpattern: Option>, + }, + + /// Foo(...) or Foo{...} or Foo, where `Foo` is a variant name from an adt with >1 variants + Variant { + adt_def: AdtDef<'tcx>, + variant_index: usize, + subpatterns: Vec>, + }, + + /// (...), Foo(...), Foo{...}, or Foo, where `Foo` is a variant name from an adt with 1 variant + Leaf { + subpatterns: Vec>, + }, + + /// box P, &P, &mut P, etc + Deref { + subpattern: Pattern<'tcx>, + }, + + Constant { + value: ConstVal, + }, + + Range { + lo: ConstVal, + hi: ConstVal, + }, + + /// matches against a slice, checking the length and extracting elements + Slice { + prefix: Vec>, + slice: Option>, + suffix: Vec>, + }, + + /// fixed match against an array, irrefutable + Array { + prefix: Vec>, + slice: Option>, + suffix: Vec>, + }, +} + +pub struct PatternContext<'a, 'gcx: 'tcx, 'tcx: 'a> { + pub tcx: TyCtxt<'a, 'gcx, 'tcx>, + pub errors: Vec, +} + +impl<'a, 'gcx, 'tcx> Pattern<'tcx> { + pub fn from_hir(tcx: TyCtxt<'a, 'gcx, 'tcx>, pat: &hir::Pat) -> Self { + let mut pcx = PatternContext::new(tcx); + let result = pcx.lower_pattern(pat); + if !pcx.errors.is_empty() { + span_bug!(pat.span, "encountered errors lowering pattern: {:?}", pcx.errors) + } + debug!("Pattern::from_hir({:?}) = {:?}", pat, result); + result + } +} + +impl<'a, 'gcx, 'tcx> PatternContext<'a, 'gcx, 'tcx> { + pub fn new(tcx: TyCtxt<'a, 'gcx, 'tcx>) -> Self { + PatternContext { tcx: tcx, errors: vec![] } + } + + pub fn lower_pattern(&mut self, pat: &hir::Pat) -> Pattern<'tcx> { + let mut ty = self.tcx.tables().node_id_to_type(pat.id); + + let kind = match pat.node { + PatKind::Wild => PatternKind::Wild, + + PatKind::Lit(ref value) => { + match eval::eval_const_expr_checked(self.tcx.global_tcx(), value) { + Ok(value) => { + PatternKind::Constant { value: value } + } + Err(e) => { + self.errors.push(PatternError::ConstEval(e)); + PatternKind::Wild + } + } + } + + PatKind::Range(ref lo, ref hi) => { + let r_lo = eval::eval_const_expr_checked(self.tcx.global_tcx(), lo); + if let Err(ref e_lo) = r_lo { + self.errors.push(PatternError::ConstEval(e_lo.clone())); + } + + let r_hi = eval::eval_const_expr_checked(self.tcx.global_tcx(), hi); + if let Err(ref e_hi) = r_hi { + self.errors.push(PatternError::ConstEval(e_hi.clone())); + } + + if let (Ok(lo), Ok(hi)) = (r_lo, r_hi) { + PatternKind::Range { lo: lo, hi: hi } + } else { + PatternKind::Wild + } + } + + PatKind::Path(..) => { + match self.tcx.expect_def(pat.id) { + Def::Const(def_id) | Def::AssociatedConst(def_id) => { + let tcx = self.tcx.global_tcx(); + let substs = tcx.tables().node_id_item_substs(pat.id) + .unwrap_or_else(|| tcx.intern_substs(&[])); + match eval::lookup_const_by_id(tcx, def_id, Some(substs)) { + Some((const_expr, _const_ty)) => { + match eval::const_expr_to_pat( + tcx, const_expr, pat.id, pat.span) + { + Ok(pat) => return self.lower_pattern(&pat), + Err(_) => { + self.errors.push(PatternError::BadConstInPattern( + pat.span, def_id)); + PatternKind::Wild + } + } + } + None => { + self.errors.push(PatternError::StaticInPattern(pat.span)); + PatternKind::Wild + } + } + } + _ => self.lower_variant_or_leaf(pat, vec![]) + } + } + + PatKind::Ref(ref subpattern, _) | + PatKind::Box(ref subpattern) => { + PatternKind::Deref { subpattern: self.lower_pattern(subpattern) } + } + + PatKind::Slice(ref prefix, ref slice, ref suffix) => { + let ty = self.tcx.tables().node_id_to_type(pat.id); + match ty.sty { + ty::TyRef(_, mt) => + PatternKind::Deref { + subpattern: Pattern { + ty: mt.ty, + span: pat.span, + kind: Box::new(self.slice_or_array_pattern( + pat.span, mt.ty, prefix, slice, suffix)) + }, + }, + + ty::TySlice(..) | + ty::TyArray(..) => + self.slice_or_array_pattern(pat.span, ty, prefix, slice, suffix), + + ref sty => + span_bug!( + pat.span, + "unexpanded type for vector pattern: {:?}", + sty), + } + } + + PatKind::Tuple(ref subpatterns, ddpos) => { + let ty = self.tcx.tables().node_id_to_type(pat.id); + match ty.sty { + ty::TyTuple(ref tys) => { + let subpatterns = + subpatterns.iter() + .enumerate_and_adjust(tys.len(), ddpos) + .map(|(i, subpattern)| FieldPattern { + field: Field::new(i), + pattern: self.lower_pattern(subpattern) + }) + .collect(); + + PatternKind::Leaf { subpatterns: subpatterns } + } + + ref sty => span_bug!(pat.span, "unexpected type for tuple pattern: {:?}", sty), + } + } + + PatKind::Binding(bm, ref ident, ref sub) => { + let def_id = self.tcx.expect_def(pat.id).def_id(); + let id = self.tcx.map.as_local_node_id(def_id).unwrap(); + let var_ty = self.tcx.tables().node_id_to_type(pat.id); + let region = match var_ty.sty { + ty::TyRef(r, _) => Some(r), + _ => None, + }; + let (mutability, mode) = match bm { + hir::BindByValue(hir::MutMutable) => + (Mutability::Mut, BindingMode::ByValue), + hir::BindByValue(hir::MutImmutable) => + (Mutability::Not, BindingMode::ByValue), + hir::BindByRef(hir::MutMutable) => + (Mutability::Not, BindingMode::ByRef(region.unwrap(), BorrowKind::Mut)), + hir::BindByRef(hir::MutImmutable) => + (Mutability::Not, BindingMode::ByRef(region.unwrap(), BorrowKind::Shared)), + }; + + // A ref x pattern is the same node used for x, and as such it has + // x's type, which is &T, where we want T (the type being matched). + if let hir::BindByRef(_) = bm { + if let ty::TyRef(_, mt) = ty.sty { + ty = mt.ty; + } else { + bug!("`ref {}` has wrong type {}", ident.node, ty); + } + } + + PatternKind::Binding { + mutability: mutability, + mode: mode, + name: ident.node, + var: id, + ty: var_ty, + subpattern: self.lower_opt_pattern(sub), + } + } + + PatKind::TupleStruct(_, ref subpatterns, ddpos) => { + let pat_ty = self.tcx.tables().node_id_to_type(pat.id); + let adt_def = match pat_ty.sty { + ty::TyAdt(adt_def, _) => adt_def, + _ => span_bug!(pat.span, "tuple struct pattern not applied to an ADT"), + }; + let variant_def = adt_def.variant_of_def(self.tcx.expect_def(pat.id)); + + let subpatterns = + subpatterns.iter() + .enumerate_and_adjust(variant_def.fields.len(), ddpos) + .map(|(i, field)| FieldPattern { + field: Field::new(i), + pattern: self.lower_pattern(field), + }) + .collect(); + self.lower_variant_or_leaf(pat, subpatterns) + } + + PatKind::Struct(_, ref fields, _) => { + let pat_ty = self.tcx.tables().node_id_to_type(pat.id); + let adt_def = match pat_ty.sty { + ty::TyAdt(adt_def, _) => adt_def, + _ => { + span_bug!( + pat.span, + "struct pattern not applied to an ADT"); + } + }; + let variant_def = adt_def.variant_of_def(self.tcx.expect_def(pat.id)); + + let subpatterns = + fields.iter() + .map(|field| { + let index = variant_def.index_of_field_named(field.node.name); + let index = index.unwrap_or_else(|| { + span_bug!( + pat.span, + "no field with name {:?}", + field.node.name); + }); + FieldPattern { + field: Field::new(index), + pattern: self.lower_pattern(&field.node.pat), + } + }) + .collect(); + + self.lower_variant_or_leaf(pat, subpatterns) + } + }; + + Pattern { + span: pat.span, + ty: ty, + kind: Box::new(kind), + } + } + + fn lower_patterns(&mut self, pats: &[P]) -> Vec> { + pats.iter().map(|p| self.lower_pattern(p)).collect() + } + + fn lower_opt_pattern(&mut self, pat: &Option>) -> Option> + { + pat.as_ref().map(|p| self.lower_pattern(p)) + } + + fn flatten_nested_slice_patterns( + &mut self, + prefix: Vec>, + slice: Option>, + suffix: Vec>) + -> (Vec>, Option>, Vec>) + { + let orig_slice = match slice { + Some(orig_slice) => orig_slice, + None => return (prefix, slice, suffix) + }; + let orig_prefix = prefix; + let orig_suffix = suffix; + + // dance because of intentional borrow-checker stupidity. + let kind = *orig_slice.kind; + match kind { + PatternKind::Slice { prefix, slice, mut suffix } | + PatternKind::Array { prefix, slice, mut suffix } => { + let mut orig_prefix = orig_prefix; + + orig_prefix.extend(prefix); + suffix.extend(orig_suffix); + + (orig_prefix, slice, suffix) + } + _ => { + (orig_prefix, Some(Pattern { + kind: box kind, ..orig_slice + }), orig_suffix) + } + } + } + + fn slice_or_array_pattern( + &mut self, + span: Span, + ty: Ty<'tcx>, + prefix: &[P], + slice: &Option>, + suffix: &[P]) + -> PatternKind<'tcx> + { + let prefix = self.lower_patterns(prefix); + let slice = self.lower_opt_pattern(slice); + let suffix = self.lower_patterns(suffix); + let (prefix, slice, suffix) = + self.flatten_nested_slice_patterns(prefix, slice, suffix); + + match ty.sty { + ty::TySlice(..) => { + // matching a slice or fixed-length array + PatternKind::Slice { prefix: prefix, slice: slice, suffix: suffix } + } + + ty::TyArray(_, len) => { + // fixed-length array + assert!(len >= prefix.len() + suffix.len()); + PatternKind::Array { prefix: prefix, slice: slice, suffix: suffix } + } + + _ => { + span_bug!(span, "bad slice pattern type {:?}", ty); + } + } + } + + fn lower_variant_or_leaf( + &mut self, + pat: &hir::Pat, + subpatterns: Vec>) + -> PatternKind<'tcx> + { + match self.tcx.expect_def(pat.id) { + Def::Variant(variant_id) | Def::VariantCtor(variant_id, ..) => { + let enum_id = self.tcx.parent_def_id(variant_id).unwrap(); + let adt_def = self.tcx.lookup_adt_def(enum_id); + if adt_def.variants.len() > 1 { + PatternKind::Variant { + adt_def: adt_def, + variant_index: adt_def.variant_index_with_id(variant_id), + subpatterns: subpatterns, + } + } else { + PatternKind::Leaf { subpatterns: subpatterns } + } + } + + Def::Struct(..) | Def::StructCtor(..) | Def::Union(..) | + Def::TyAlias(..) | Def::AssociatedTy(..) | Def::SelfTy(..) => { + PatternKind::Leaf { subpatterns: subpatterns } + } + + def => { + span_bug!(pat.span, "inappropriate def for pattern: {:?}", def); + } + } + } +} + +pub trait PatternFoldable<'tcx> : Sized { + fn fold_with>(&self, folder: &mut F) -> Self { + self.super_fold_with(folder) + } + + fn super_fold_with>(&self, folder: &mut F) -> Self; +} + +pub trait PatternFolder<'tcx> : Sized { + fn fold_pattern(&mut self, pattern: &Pattern<'tcx>) -> Pattern<'tcx> { + pattern.super_fold_with(self) + } + + fn fold_pattern_kind(&mut self, kind: &PatternKind<'tcx>) -> PatternKind<'tcx> { + kind.super_fold_with(self) + } +} + + +impl<'tcx, T: PatternFoldable<'tcx>> PatternFoldable<'tcx> for Box { + fn super_fold_with>(&self, folder: &mut F) -> Self { + let content: T = (**self).fold_with(folder); + box content + } +} + +impl<'tcx, T: PatternFoldable<'tcx>> PatternFoldable<'tcx> for Vec { + fn super_fold_with>(&self, folder: &mut F) -> Self { + self.iter().map(|t| t.fold_with(folder)).collect() + } +} + +impl<'tcx, T: PatternFoldable<'tcx>> PatternFoldable<'tcx> for Option { + fn super_fold_with>(&self, folder: &mut F) -> Self{ + self.as_ref().map(|t| t.fold_with(folder)) + } +} + +macro_rules! CopyImpls { + ($($ty:ty),+) => { + $( + impl<'tcx> PatternFoldable<'tcx> for $ty { + fn super_fold_with>(&self, _: &mut F) -> Self { + self.clone() + } + } + )+ + } +} + +macro_rules! TcxCopyImpls { + ($($ty:ident),+) => { + $( + impl<'tcx> PatternFoldable<'tcx> for $ty<'tcx> { + fn super_fold_with>(&self, _: &mut F) -> Self { + *self + } + } + )+ + } +} + +CopyImpls!{ Span, Field, Mutability, ast::Name, ast::NodeId, usize, ConstVal } +TcxCopyImpls!{ Ty, BindingMode, AdtDef } + +impl<'tcx> PatternFoldable<'tcx> for FieldPattern<'tcx> { + fn super_fold_with>(&self, folder: &mut F) -> Self { + FieldPattern { + field: self.field.fold_with(folder), + pattern: self.pattern.fold_with(folder) + } + } +} + +impl<'tcx> PatternFoldable<'tcx> for Pattern<'tcx> { + fn fold_with>(&self, folder: &mut F) -> Self { + folder.fold_pattern(self) + } + + fn super_fold_with>(&self, folder: &mut F) -> Self { + Pattern { + ty: self.ty.fold_with(folder), + span: self.span.fold_with(folder), + kind: self.kind.fold_with(folder) + } + } +} + +impl<'tcx> PatternFoldable<'tcx> for PatternKind<'tcx> { + fn fold_with>(&self, folder: &mut F) -> Self { + folder.fold_pattern_kind(self) + } + + fn super_fold_with>(&self, folder: &mut F) -> Self { + match *self { + PatternKind::Wild => PatternKind::Wild, + PatternKind::Binding { + mutability, + name, + mode, + var, + ty, + ref subpattern, + } => PatternKind::Binding { + mutability: mutability.fold_with(folder), + name: name.fold_with(folder), + mode: mode.fold_with(folder), + var: var.fold_with(folder), + ty: ty.fold_with(folder), + subpattern: subpattern.fold_with(folder), + }, + PatternKind::Variant { + adt_def, + variant_index, + ref subpatterns, + } => PatternKind::Variant { + adt_def: adt_def.fold_with(folder), + variant_index: variant_index.fold_with(folder), + subpatterns: subpatterns.fold_with(folder) + }, + PatternKind::Leaf { + ref subpatterns, + } => PatternKind::Leaf { + subpatterns: subpatterns.fold_with(folder), + }, + PatternKind::Deref { + ref subpattern, + } => PatternKind::Deref { + subpattern: subpattern.fold_with(folder), + }, + PatternKind::Constant { + ref value + } => PatternKind::Constant { + value: value.fold_with(folder) + }, + PatternKind::Range { + ref lo, + ref hi + } => PatternKind::Range { + lo: lo.fold_with(folder), + hi: hi.fold_with(folder) + }, + PatternKind::Slice { + ref prefix, + ref slice, + ref suffix, + } => PatternKind::Slice { + prefix: prefix.fold_with(folder), + slice: slice.fold_with(folder), + suffix: suffix.fold_with(folder) + }, + PatternKind::Array { + ref prefix, + ref slice, + ref suffix + } => PatternKind::Array { + prefix: prefix.fold_with(folder), + slice: slice.fold_with(folder), + suffix: suffix.fold_with(folder) + }, + } + } +} diff --git a/src/librustc_data_structures/accumulate_vec.rs b/src/librustc_data_structures/accumulate_vec.rs new file mode 100644 index 0000000000..3894db4027 --- /dev/null +++ b/src/librustc_data_structures/accumulate_vec.rs @@ -0,0 +1,52 @@ +// Copyright 2016 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +//! A vector type intended to be used for collecting from iterators onto the stack. +//! +//! Space for up to N elements is provided on the stack. If more elements are collected, Vec is +//! used to store the values on the heap. This type does not support re-allocating onto the heap, +//! and there is no way to push more elements onto the existing storage. +//! +//! The N above is determined by Array's implementor, by way of an associatated constant. + +use std::ops::Deref; +use std::iter::{IntoIterator, FromIterator}; + +use array_vec::{Array, ArrayVec}; + +#[derive(Debug)] +pub enum AccumulateVec { + Array(ArrayVec), + Heap(Vec) +} + +impl Deref for AccumulateVec { + type Target = [A::Element]; + fn deref(&self) -> &Self::Target { + match *self { + AccumulateVec::Array(ref v) => &v[..], + AccumulateVec::Heap(ref v) => &v[..], + } + } +} + +impl FromIterator for AccumulateVec { + fn from_iter(iter: I) -> AccumulateVec where I: IntoIterator { + let iter = iter.into_iter(); + if iter.size_hint().1.map_or(false, |n| n <= A::LEN) { + let mut v = ArrayVec::new(); + v.extend(iter); + AccumulateVec::Array(v) + } else { + AccumulateVec::Heap(iter.collect()) + } + } +} + diff --git a/src/librustc_data_structures/array_vec.rs b/src/librustc_data_structures/array_vec.rs new file mode 100644 index 0000000000..f87426cee5 --- /dev/null +++ b/src/librustc_data_structures/array_vec.rs @@ -0,0 +1,106 @@ +// Copyright 2016 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +//! A stack-allocated vector, allowing storage of N elements on the stack. +//! +//! Currently, only the N = 8 case is supported (due to Array only being impl-ed for [T; 8]). + +use std::marker::Unsize; +use std::iter::Extend; +use std::ptr::drop_in_place; +use std::ops::{Deref, DerefMut}; +use std::slice; +use std::fmt; + +pub unsafe trait Array { + type Element; + type PartialStorage: Default + Unsize<[ManuallyDrop]>; + const LEN: usize; +} + +unsafe impl Array for [T; 8] { + type Element = T; + type PartialStorage = [ManuallyDrop; 8]; + const LEN: usize = 8; +} + +pub struct ArrayVec { + count: usize, + values: A::PartialStorage +} + +impl ArrayVec { + pub fn new() -> Self { + ArrayVec { + count: 0, + values: Default::default(), + } + } +} + +impl fmt::Debug for ArrayVec + where A: Array, + A::Element: fmt::Debug { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + self[..].fmt(f) + } +} + +impl Deref for ArrayVec { + type Target = [A::Element]; + fn deref(&self) -> &Self::Target { + unsafe { + slice::from_raw_parts(&self.values as *const _ as *const A::Element, self.count) + } + } +} + +impl DerefMut for ArrayVec { + fn deref_mut(&mut self) -> &mut [A::Element] { + unsafe { + slice::from_raw_parts_mut(&mut self.values as *mut _ as *mut A::Element, self.count) + } + } +} + +impl Drop for ArrayVec { + fn drop(&mut self) { + unsafe { + drop_in_place(&mut self[..]) + } + } +} + +impl Extend for ArrayVec { + fn extend(&mut self, iter: I) where I: IntoIterator { + for el in iter { + unsafe { + let arr = &mut self.values as &mut [ManuallyDrop<_>]; + arr[self.count].value = el; + } + self.count += 1; + } + } +} + +// FIXME: This should use repr(transparent) from rust-lang/rfcs#1758. +#[allow(unions_with_drop_fields)] +pub union ManuallyDrop { + value: T, + #[allow(dead_code)] + empty: (), +} + +impl Default for ManuallyDrop { + fn default() -> Self { + ManuallyDrop { empty: () } + } +} + diff --git a/src/librustc_borrowck/bitslice.rs b/src/librustc_data_structures/bitslice.rs similarity index 98% rename from src/librustc_borrowck/bitslice.rs rename to src/librustc_data_structures/bitslice.rs index 80fa86a007..ba53578e57 100644 --- a/src/librustc_borrowck/bitslice.rs +++ b/src/librustc_data_structures/bitslice.rs @@ -8,8 +8,7 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -// FIXME: move this to `rustc_data_structures` and potentially merge -// with `bitvec` there. +// FIXME: merge with `bitvec` use std::mem; diff --git a/src/librustc_data_structures/blake2b.rs b/src/librustc_data_structures/blake2b.rs new file mode 100644 index 0000000000..8c82c135dc --- /dev/null +++ b/src/librustc_data_structures/blake2b.rs @@ -0,0 +1,338 @@ +// Copyright 2016 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + + +// An implementation of the Blake2b cryptographic hash function. +// The implementation closely follows: https://tools.ietf.org/html/rfc7693 +// +// "BLAKE2 is a cryptographic hash function faster than MD5, SHA-1, SHA-2, and +// SHA-3, yet is at least as secure as the latest standard SHA-3." +// according to their own website :) +// +// Indeed this implementation is two to three times as fast as our SHA-256 +// implementation. If you have the luxury of being able to use crates from +// crates.io, you can go there and find still faster implementations. + +use std::mem; +use std::slice; + +pub struct Blake2bCtx { + b: [u8; 128], + h: [u64; 8], + t: [u64; 2], + c: usize, + outlen: u16, + finalized: bool +} + +impl ::std::fmt::Debug for Blake2bCtx { + fn fmt(&self, fmt: &mut ::std::fmt::Formatter) -> Result<(), ::std::fmt::Error> { + try!(write!(fmt, "hash: ")); + for v in &self.h[..] { + try!(write!(fmt, "{:x}", v)); + } + Ok(()) + } +} + +#[inline(always)] +fn b2b_g(v: &mut [u64; 16], + a: usize, + b: usize, + c: usize, + d: usize, + x: u64, + y: u64) +{ + v[a] = v[a].wrapping_add(v[b]).wrapping_add(x); + v[d] = (v[d] ^ v[a]).rotate_right(32); + v[c] = v[c].wrapping_add(v[d]); + v[b] = (v[b] ^ v[c]).rotate_right(24); + v[a] = v[a].wrapping_add(v[b]).wrapping_add(y); + v[d] = (v[d] ^ v[a]).rotate_right(16); + v[c] = v[c].wrapping_add(v[d]); + v[b] = (v[b] ^ v[c]).rotate_right(63); +} + +// Initialization vector +const BLAKE2B_IV: [u64; 8] = [ + 0x6A09E667F3BCC908, 0xBB67AE8584CAA73B, + 0x3C6EF372FE94F82B, 0xA54FF53A5F1D36F1, + 0x510E527FADE682D1, 0x9B05688C2B3E6C1F, + 0x1F83D9ABFB41BD6B, 0x5BE0CD19137E2179 +]; + +fn blake2b_compress(ctx: &mut Blake2bCtx, last: bool) { + + const SIGMA: [[usize; 16]; 12] = [ + [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15 ], + [14, 10, 4, 8, 9, 15, 13, 6, 1, 12, 0, 2, 11, 7, 5, 3 ], + [11, 8, 12, 0, 5, 2, 15, 13, 10, 14, 3, 6, 7, 1, 9, 4 ], + [7, 9, 3, 1, 13, 12, 11, 14, 2, 6, 5, 10, 4, 0, 15, 8 ], + [9, 0, 5, 7, 2, 4, 10, 15, 14, 1, 11, 12, 6, 8, 3, 13 ], + [2, 12, 6, 10, 0, 11, 8, 3, 4, 13, 7, 5, 15, 14, 1, 9 ], + [12, 5, 1, 15, 14, 13, 4, 10, 0, 7, 6, 3, 9, 2, 8, 11 ], + [13, 11, 7, 14, 12, 1, 3, 9, 5, 0, 15, 4, 8, 6, 2, 10 ], + [6, 15, 14, 9, 11, 3, 0, 8, 12, 2, 13, 7, 1, 4, 10, 5 ], + [10, 2, 8, 4, 7, 6, 1, 5, 15, 11, 9, 14, 3, 12, 13, 0 ], + [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15 ], + [14, 10, 4, 8, 9, 15, 13, 6, 1, 12, 0, 2, 11, 7, 5, 3 ] + ]; + + let mut v: [u64; 16] = [ + ctx.h[0], + ctx.h[1], + ctx.h[2], + ctx.h[3], + ctx.h[4], + ctx.h[5], + ctx.h[6], + ctx.h[7], + + BLAKE2B_IV[0], + BLAKE2B_IV[1], + BLAKE2B_IV[2], + BLAKE2B_IV[3], + BLAKE2B_IV[4], + BLAKE2B_IV[5], + BLAKE2B_IV[6], + BLAKE2B_IV[7], + ]; + + v[12] ^= ctx.t[0]; // low 64 bits of offset + v[13] ^= ctx.t[1]; // high 64 bits + if last { + v[14] = !v[14]; + } + + { + // Re-interpret the input buffer in the state as u64s + let m: &mut [u64; 16] = unsafe { + let b: &mut [u8; 128] = &mut ctx.b; + ::std::mem::transmute(b) + }; + + // It's OK to modify the buffer in place since this is the last time + // this data will be accessed before it's overwritten + if cfg!(target_endian = "big") { + for word in &mut m[..] { + *word = word.to_be(); + } + } + + for i in 0 .. 12 { + b2b_g(&mut v, 0, 4, 8, 12, m[SIGMA[i][ 0]], m[SIGMA[i][ 1]]); + b2b_g(&mut v, 1, 5, 9, 13, m[SIGMA[i][ 2]], m[SIGMA[i][ 3]]); + b2b_g(&mut v, 2, 6, 10, 14, m[SIGMA[i][ 4]], m[SIGMA[i][ 5]]); + b2b_g(&mut v, 3, 7, 11, 15, m[SIGMA[i][ 6]], m[SIGMA[i][ 7]]); + b2b_g(&mut v, 0, 5, 10, 15, m[SIGMA[i][ 8]], m[SIGMA[i][ 9]]); + b2b_g(&mut v, 1, 6, 11, 12, m[SIGMA[i][10]], m[SIGMA[i][11]]); + b2b_g(&mut v, 2, 7, 8, 13, m[SIGMA[i][12]], m[SIGMA[i][13]]); + b2b_g(&mut v, 3, 4, 9, 14, m[SIGMA[i][14]], m[SIGMA[i][15]]); + } + } + + for i in 0 .. 8 { + ctx.h[i] ^= v[i] ^ v[i + 8]; + } +} + +fn blake2b_new(outlen: usize, key: &[u8]) -> Blake2bCtx { + assert!(outlen > 0 && outlen <= 64 && key.len() <= 64); + + let mut ctx = Blake2bCtx { + b: [0; 128], + h: BLAKE2B_IV, + t: [0; 2], + c: 0, + outlen: outlen as u16, + finalized: false, + }; + + ctx.h[0] ^= 0x01010000 ^ ((key.len() << 8) as u64) ^ (outlen as u64); + + if key.len() > 0 { + blake2b_update(&mut ctx, key); + ctx.c = ctx.b.len(); + } + + ctx +} + +fn blake2b_update(ctx: &mut Blake2bCtx, mut data: &[u8]) { + assert!(!ctx.finalized, "Blake2bCtx already finalized"); + + let mut bytes_to_copy = data.len(); + let mut space_in_buffer = ctx.b.len() - ctx.c; + + while bytes_to_copy > space_in_buffer { + checked_mem_copy(data, &mut ctx.b[ctx.c .. ], space_in_buffer); + + ctx.t[0] = ctx.t[0].wrapping_add(ctx.b.len() as u64); + if ctx.t[0] < (ctx.b.len() as u64) { + ctx.t[1] += 1; + } + blake2b_compress(ctx, false); + ctx.c = 0; + + data = &data[space_in_buffer .. ]; + bytes_to_copy -= space_in_buffer; + space_in_buffer = ctx.b.len(); + } + + if bytes_to_copy > 0 { + checked_mem_copy(data, &mut ctx.b[ctx.c .. ], bytes_to_copy); + ctx.c += bytes_to_copy; + } +} + +fn blake2b_final(ctx: &mut Blake2bCtx) +{ + assert!(!ctx.finalized, "Blake2bCtx already finalized"); + + ctx.t[0] = ctx.t[0].wrapping_add(ctx.c as u64); + if ctx.t[0] < ctx.c as u64 { + ctx.t[1] += 1; + } + + while ctx.c < 128 { + ctx.b[ctx.c] = 0; + ctx.c += 1; + } + + blake2b_compress(ctx, true); + + if cfg!(target_endian = "big") { + // Make sure that the data is in memory in little endian format, as is + // demanded by BLAKE2 + for word in &mut ctx.h { + *word = word.to_le(); + } + } + + ctx.finalized = true; +} + +#[inline(always)] +fn checked_mem_copy(from: &[T1], to: &mut [T2], byte_count: usize) { + let from_size = from.len() * mem::size_of::(); + let to_size = to.len() * mem::size_of::(); + assert!(from_size >= byte_count); + assert!(to_size >= byte_count); + let from_byte_ptr = from.as_ptr() as * const u8; + let to_byte_ptr = to.as_mut_ptr() as * mut u8; + unsafe { + ::std::ptr::copy_nonoverlapping(from_byte_ptr, to_byte_ptr, byte_count); + } +} + +pub fn blake2b(out: &mut [u8], key: &[u8], data: &[u8]) +{ + let mut ctx = blake2b_new(out.len(), key); + blake2b_update(&mut ctx, data); + blake2b_final(&mut ctx); + checked_mem_copy(&ctx.h, out, ctx.outlen as usize); +} + +pub struct Blake2bHasher(Blake2bCtx); + +impl ::std::hash::Hasher for Blake2bHasher { + fn write(&mut self, bytes: &[u8]) { + blake2b_update(&mut self.0, bytes); + } + + fn finish(&self) -> u64 { + assert!(self.0.outlen == 8, + "Hasher initialized with incompatible output length"); + u64::from_le(self.0.h[0]) + } +} + +impl Blake2bHasher { + pub fn new(outlen: usize, key: &[u8]) -> Blake2bHasher { + Blake2bHasher(blake2b_new(outlen, key)) + } + + pub fn finalize(&mut self) -> &[u8] { + if !self.0.finalized { + blake2b_final(&mut self.0); + } + debug_assert!(mem::size_of_val(&self.0.h) >= self.0.outlen as usize); + let raw_ptr = (&self.0.h[..]).as_ptr() as * const u8; + unsafe { + slice::from_raw_parts(raw_ptr, self.0.outlen as usize) + } + } +} + +impl ::std::fmt::Debug for Blake2bHasher { + fn fmt(&self, fmt: &mut ::std::fmt::Formatter) -> Result<(), ::std::fmt::Error> { + write!(fmt, "{:?}", self.0) + } +} + +#[cfg(test)] +fn selftest_seq(out: &mut [u8], seed: u32) +{ + let mut a: u32 = 0xDEAD4BADu32.wrapping_mul(seed); + let mut b: u32 = 1; + + for i in 0 .. out.len() { + let t: u32 = a.wrapping_add(b); + a = b; + b = t; + out[i] = ((t >> 24) & 0xFF) as u8; + } +} + +#[test] +fn blake2b_selftest() +{ + use std::hash::Hasher; + + // grand hash of hash results + const BLAKE2B_RES: [u8; 32] = [ + 0xC2, 0x3A, 0x78, 0x00, 0xD9, 0x81, 0x23, 0xBD, + 0x10, 0xF5, 0x06, 0xC6, 0x1E, 0x29, 0xDA, 0x56, + 0x03, 0xD7, 0x63, 0xB8, 0xBB, 0xAD, 0x2E, 0x73, + 0x7F, 0x5E, 0x76, 0x5A, 0x7B, 0xCC, 0xD4, 0x75 + ]; + + // parameter sets + const B2B_MD_LEN: [usize; 4] = [20, 32, 48, 64]; + const B2B_IN_LEN: [usize; 6] = [0, 3, 128, 129, 255, 1024]; + + let mut data = [0u8; 1024]; + let mut md = [0u8; 64]; + let mut key = [0u8; 64]; + + let mut hasher = Blake2bHasher::new(32, &[]); + + for i in 0 .. 4 { + let outlen = B2B_MD_LEN[i]; + for j in 0 .. 6 { + let inlen = B2B_IN_LEN[j]; + + selftest_seq(&mut data[.. inlen], inlen as u32); // unkeyed hash + blake2b(&mut md[.. outlen], &[], &data[.. inlen]); + hasher.write(&md[.. outlen]); // hash the hash + + selftest_seq(&mut key[0 .. outlen], outlen as u32); // keyed hash + blake2b(&mut md[.. outlen], &key[.. outlen], &data[.. inlen]); + hasher.write(&md[.. outlen]); // hash the hash + } + } + + // compute and compare the hash of hashes + let md = hasher.finalize(); + for i in 0 .. 32 { + assert_eq!(md[i], BLAKE2B_RES[i]); + } +} diff --git a/src/librustc_data_structures/control_flow_graph/dominators/mod.rs b/src/librustc_data_structures/control_flow_graph/dominators/mod.rs index 250b89d12e..ab675db215 100644 --- a/src/librustc_data_structures/control_flow_graph/dominators/mod.rs +++ b/src/librustc_data_structures/control_flow_graph/dominators/mod.rs @@ -57,9 +57,9 @@ pub fn dominators_given_rpo(graph: &G, // (*) // (*) dominators for `pred` have been calculated new_idom = intersect_opt(&post_order_rank, - &immediate_dominators, - new_idom, - Some(pred)); + &immediate_dominators, + new_idom, + Some(pred)); } } @@ -77,10 +77,10 @@ pub fn dominators_given_rpo(graph: &G, } fn intersect_opt(post_order_rank: &IndexVec, - immediate_dominators: &IndexVec>, - node1: Option, - node2: Option) - -> Option { + immediate_dominators: &IndexVec>, + node1: Option, + node2: Option) + -> Option { match (node1, node2) { (None, None) => None, (Some(n), None) | (None, Some(n)) => Some(n), @@ -89,10 +89,10 @@ fn intersect_opt(post_order_rank: &IndexVec, } fn intersect(post_order_rank: &IndexVec, - immediate_dominators: &IndexVec>, - mut node1: Node, - mut node2: Node) - -> Node { + immediate_dominators: &IndexVec>, + mut node1: Node, + mut node2: Node) + -> Node { while node1 != node2 { while post_order_rank[node1] < post_order_rank[node2] { node1 = immediate_dominators[node1].unwrap(); @@ -142,9 +142,9 @@ impl Dominators { "node {:?} is not reachable", node2); intersect::(&self.post_order_rank, - &self.immediate_dominators, - node1, - node2) + &self.immediate_dominators, + node1, + node2) } pub fn mutual_dominator(&self, iter: I) -> Option diff --git a/src/librustc_data_structures/control_flow_graph/dominators/test.rs b/src/librustc_data_structures/control_flow_graph/dominators/test.rs index a6db5f2fe3..0af878cac2 100644 --- a/src/librustc_data_structures/control_flow_graph/dominators/test.rs +++ b/src/librustc_data_structures/control_flow_graph/dominators/test.rs @@ -14,12 +14,7 @@ use super::*; #[test] fn diamond() { - let graph = TestGraph::new(0, &[ - (0, 1), - (0, 2), - (1, 3), - (2, 3), - ]); + let graph = TestGraph::new(0, &[(0, 1), (0, 2), (1, 3), (2, 3)]); let dominators = dominators(&graph); let immediate_dominators = dominators.all_immediate_dominators(); @@ -32,17 +27,9 @@ fn diamond() { #[test] fn paper() { // example from the paper: - let graph = TestGraph::new(6, &[ - (6, 5), - (6, 4), - (5, 1), - (4, 2), - (4, 3), - (1, 2), - (2, 3), - (3, 2), - (2, 1), - ]); + let graph = TestGraph::new(6, + &[(6, 5), (6, 4), (5, 1), (4, 2), (4, 3), (1, 2), (2, 3), (3, 2), + (2, 1)]); let dominators = dominators(&graph); let immediate_dominators = dominators.all_immediate_dominators(); @@ -54,4 +41,3 @@ fn paper() { assert_eq!(immediate_dominators[5], Some(6)); assert_eq!(immediate_dominators[6], Some(6)); } - diff --git a/src/librustc_data_structures/control_flow_graph/iterate/test.rs b/src/librustc_data_structures/control_flow_graph/iterate/test.rs index 28297d55bd..dca45602f1 100644 --- a/src/librustc_data_structures/control_flow_graph/iterate/test.rs +++ b/src/librustc_data_structures/control_flow_graph/iterate/test.rs @@ -15,12 +15,7 @@ use super::*; #[test] fn diamond_post_order() { - let graph = TestGraph::new(0, &[ - (0, 1), - (0, 2), - (1, 3), - (2, 3), - ]); + let graph = TestGraph::new(0, &[(0, 1), (0, 2), (1, 3), (2, 3)]); let result = post_order_from(&graph, 0); assert_eq!(result, vec![3, 1, 2, 0]); @@ -33,16 +28,8 @@ fn rev_post_order_inner_loop() { // ^ ^ v | // | 6 <- 4 | // +-----------------+ - let graph = TestGraph::new(0, &[ - (0, 1), - (1, 2), - (2, 3), - (3, 5), - (3, 1), - (2, 4), - (4, 6), - (6, 2), - ]); + let graph = TestGraph::new(0, + &[(0, 1), (1, 2), (2, 3), (3, 5), (3, 1), (2, 4), (4, 6), (6, 2)]); let rev_graph = TransposedGraph::new(&graph); @@ -52,4 +39,3 @@ fn rev_post_order_inner_loop() { let result = post_order_from_to(&rev_graph, 3, Some(1)); assert_eq!(result, vec![4, 6, 2, 3]); } - diff --git a/src/librustc_data_structures/control_flow_graph/mod.rs b/src/librustc_data_structures/control_flow_graph/mod.rs index f9e75b12e0..eb6839df62 100644 --- a/src/librustc_data_structures/control_flow_graph/mod.rs +++ b/src/librustc_data_structures/control_flow_graph/mod.rs @@ -36,10 +36,10 @@ pub trait ControlFlowGraph pub trait GraphPredecessors<'graph> { type Item; - type Iter: Iterator; + type Iter: Iterator; } pub trait GraphSuccessors<'graph> { type Item; - type Iter: Iterator; -} \ No newline at end of file + type Iter: Iterator; +} diff --git a/src/librustc_data_structures/control_flow_graph/reachable/mod.rs b/src/librustc_data_structures/control_flow_graph/reachable/mod.rs index e520e23f3a..24210ebb95 100644 --- a/src/librustc_data_structures/control_flow_graph/reachable/mod.rs +++ b/src/librustc_data_structures/control_flow_graph/reachable/mod.rs @@ -19,8 +19,7 @@ use super::super::indexed_vec::{IndexVec, Idx}; #[cfg(test)] mod test; -pub fn reachable(graph: &G) - -> Reachability { +pub fn reachable(graph: &G) -> Reachability { let reverse_post_order = reverse_post_order(graph, graph.start_node()); reachable_given_rpo(graph, &reverse_post_order) } @@ -53,12 +52,10 @@ pub struct Reachability { impl Reachability { fn new(graph: &G) -> Self { let num_nodes = graph.num_nodes(); - Reachability { - bits: IndexVec::from_elem_n(BitVector::new(num_nodes), num_nodes), - } + Reachability { bits: IndexVec::from_elem_n(BitVector::new(num_nodes), num_nodes) } } - pub fn can_reach(&self, source: Node, target: Node)-> bool { + pub fn can_reach(&self, source: Node, target: Node) -> bool { let bit: usize = target.index(); self.bits[source].contains(bit) } diff --git a/src/librustc_data_structures/control_flow_graph/reachable/test.rs b/src/librustc_data_structures/control_flow_graph/reachable/test.rs index 6aa906a080..ef45deeaaf 100644 --- a/src/librustc_data_structures/control_flow_graph/reachable/test.rs +++ b/src/librustc_data_structures/control_flow_graph/reachable/test.rs @@ -17,15 +17,7 @@ fn test1() { // 0 -> 1 -> 2 -> 3 // ^ v // 6 <- 4 -> 5 - let graph = TestGraph::new(0, &[ - (0, 1), - (1, 2), - (2, 3), - (2, 4), - (4, 5), - (4, 6), - (6, 1), - ]); + let graph = TestGraph::new(0, &[(0, 1), (1, 2), (2, 3), (2, 4), (4, 5), (4, 6), (6, 1)]); let reachable = reachable(&graph); assert!((0..6).all(|i| reachable.can_reach(0, i))); assert!((1..6).all(|i| reachable.can_reach(1, i))); @@ -43,15 +35,9 @@ fn test2() { // 30 -> 31 -> 32 -> 33 // ^ v // 36 <- 34 -> 35 - let graph = TestGraph::new(30, &[ - (30, 31), - (31, 32), - (32, 33), - (32, 34), - (34, 35), - (34, 36), - (36, 31), - ]); + let graph = TestGraph::new(30, + &[(30, 31), (31, 32), (32, 33), (32, 34), (34, 35), (34, 36), + (36, 31)]); let reachable = reachable(&graph); assert!((30..36).all(|i| reachable.can_reach(30, i))); assert!((31..36).all(|i| reachable.can_reach(31, i))); diff --git a/src/librustc_data_structures/control_flow_graph/reference.rs b/src/librustc_data_structures/control_flow_graph/reference.rs index d735be1ed2..3b8b01f2ff 100644 --- a/src/librustc_data_structures/control_flow_graph/reference.rs +++ b/src/librustc_data_structures/control_flow_graph/reference.rs @@ -21,13 +21,13 @@ impl<'graph, G: ControlFlowGraph> ControlFlowGraph for &'graph G { (**self).start_node() } - fn predecessors<'iter>(&'iter self, node: Self::Node) - -> >::Iter { + fn predecessors<'iter>(&'iter self, + node: Self::Node) + -> >::Iter { (**self).predecessors(node) } - fn successors<'iter>(&'iter self, node: Self::Node) - -> >::Iter { + fn successors<'iter>(&'iter self, node: Self::Node) -> >::Iter { (**self).successors(node) } } diff --git a/src/librustc_data_structures/control_flow_graph/test.rs b/src/librustc_data_structures/control_flow_graph/test.rs index 57b2a858de..d48a6e684a 100644 --- a/src/librustc_data_structures/control_flow_graph/test.rs +++ b/src/librustc_data_structures/control_flow_graph/test.rs @@ -28,7 +28,7 @@ impl TestGraph { num_nodes: start_node + 1, start_node: start_node, successors: HashMap::new(), - predecessors: HashMap::new() + predecessors: HashMap::new(), }; for &(source, target) in edges { graph.num_nodes = max(graph.num_nodes, source + 1); @@ -55,13 +55,13 @@ impl ControlFlowGraph for TestGraph { self.num_nodes } - fn predecessors<'graph>(&'graph self, node: usize) + fn predecessors<'graph>(&'graph self, + node: usize) -> >::Iter { - self.predecessors[&node].iter().cloned() + self.predecessors[&node].iter().cloned() } - fn successors<'graph>(&'graph self, node: usize) - -> >::Iter { + fn successors<'graph>(&'graph self, node: usize) -> >::Iter { self.successors[&node].iter().cloned() } } @@ -75,4 +75,3 @@ impl<'graph> GraphSuccessors<'graph> for TestGraph { type Item = usize; type Iter = iter::Cloned>; } - diff --git a/src/librustc_data_structures/control_flow_graph/transpose.rs b/src/librustc_data_structures/control_flow_graph/transpose.rs index 792e079c28..a1a117edb9 100644 --- a/src/librustc_data_structures/control_flow_graph/transpose.rs +++ b/src/librustc_data_structures/control_flow_graph/transpose.rs @@ -22,7 +22,10 @@ impl TransposedGraph { } pub fn with_start(base_graph: G, start_node: G::Node) -> Self { - TransposedGraph { base_graph: base_graph, start_node: start_node } + TransposedGraph { + base_graph: base_graph, + start_node: start_node, + } } } @@ -37,12 +40,14 @@ impl ControlFlowGraph for TransposedGraph { self.start_node } - fn predecessors<'graph>(&'graph self, node: Self::Node) + fn predecessors<'graph>(&'graph self, + node: Self::Node) -> >::Iter { self.base_graph.successors(node) } - fn successors<'graph>(&'graph self, node: Self::Node) + fn successors<'graph>(&'graph self, + node: Self::Node) -> >::Iter { self.base_graph.predecessors(node) } diff --git a/src/librustc_data_structures/fmt_wrap.rs b/src/librustc_data_structures/fmt_wrap.rs new file mode 100644 index 0000000000..50fd1d802b --- /dev/null +++ b/src/librustc_data_structures/fmt_wrap.rs @@ -0,0 +1,31 @@ +// Copyright 2016 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +use std::fmt; + +// Provide some more formatting options for some data types (at the moment +// that's just `{:x}` for slices of u8). + +pub struct FmtWrap(pub T); + +impl<'a> fmt::LowerHex for FmtWrap<&'a [u8]> { + fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result { + for byte in self.0.iter() { + try!(write!(formatter, "{:02x}", byte)); + } + Ok(()) + } +} + +#[test] +fn test_lower_hex() { + let bytes: &[u8] = &[0x01, 0x23, 0x45, 0x67, 0x89, 0xab, 0xcd, 0xef]; + assert_eq!("0123456789abcdef", &format!("{:x}", FmtWrap(bytes))); +} diff --git a/src/librustc_data_structures/graph/mod.rs b/src/librustc_data_structures/graph/mod.rs index 4561a3d084..fdb629ca5a 100644 --- a/src/librustc_data_structures/graph/mod.rs +++ b/src/librustc_data_structures/graph/mod.rs @@ -380,7 +380,7 @@ impl<'g, N: Debug, E: Debug> DepthFirstTraversal<'g, N, E> { graph: graph, stack: vec![], visited: visited, - direction: direction + direction: direction, } } @@ -394,7 +394,7 @@ impl<'g, N: Debug, E: Debug> DepthFirstTraversal<'g, N, E> { graph: graph, stack: vec![start_node], visited: visited, - direction: direction + direction: direction, } } diff --git a/src/librustc_borrowck/indexed_set.rs b/src/librustc_data_structures/indexed_set.rs similarity index 98% rename from src/librustc_borrowck/indexed_set.rs rename to src/librustc_data_structures/indexed_set.rs index 671aff97d2..2e9e054e97 100644 --- a/src/librustc_borrowck/indexed_set.rs +++ b/src/librustc_data_structures/indexed_set.rs @@ -8,16 +8,13 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -// FIXME: move this to `rustc_data_structures` - use std::fmt; use std::marker::PhantomData; use std::mem; use std::ops::{Deref, DerefMut, Range}; use bitslice::{BitSlice, Word}; use bitslice::{bitwise, Union, Subtract}; - -use rustc_data_structures::indexed_vec::Idx; +use indexed_vec::Idx; /// Represents a set (or packed family of sets), of some element type /// E, where each E is identified by some unique index type `T`. diff --git a/src/librustc_data_structures/indexed_vec.rs b/src/librustc_data_structures/indexed_vec.rs index 9123463149..00cea9cbdf 100644 --- a/src/librustc_data_structures/indexed_vec.rs +++ b/src/librustc_data_structures/indexed_vec.rs @@ -149,6 +149,21 @@ impl IndexVec { pub fn last(&self) -> Option { self.len().checked_sub(1).map(I::new) } + + #[inline] + pub fn shrink_to_fit(&mut self) { + self.raw.shrink_to_fit() + } + + #[inline] + pub fn swap(&mut self, a: usize, b: usize) { + self.raw.swap(a, b) + } + + #[inline] + pub fn truncate(&mut self, a: usize) { + self.raw.truncate(a) + } } impl Index for IndexVec { diff --git a/src/librustc_data_structures/lib.rs b/src/librustc_data_structures/lib.rs index e7da18cef1..fc963dac94 100644 --- a/src/librustc_data_structures/lib.rs +++ b/src/librustc_data_structures/lib.rs @@ -30,6 +30,9 @@ #![feature(staged_api)] #![feature(unboxed_closures)] #![feature(fn_traits)] +#![feature(untagged_unions)] +#![feature(associated_consts)] +#![feature(unsize)] #![cfg_attr(unix, feature(libc))] #![cfg_attr(test, feature(test))] @@ -41,9 +44,15 @@ extern crate serialize as rustc_serialize; // used by deriving #[cfg(unix)] extern crate libc; +pub mod array_vec; +pub mod accumulate_vec; +pub mod bitslice; +pub mod blake2b; pub mod bitvec; +pub mod fmt_wrap; pub mod graph; pub mod ivar; +pub mod indexed_set; pub mod indexed_vec; pub mod obligation_forest; pub mod snapshot_map; diff --git a/src/librustc_data_structures/obligation_forest/mod.rs b/src/librustc_data_structures/obligation_forest/mod.rs index c079146edb..a2bfa784e8 100644 --- a/src/librustc_data_structures/obligation_forest/mod.rs +++ b/src/librustc_data_structures/obligation_forest/mod.rs @@ -333,6 +333,7 @@ impl ObligationForest { } } Err(err) => { + stalled = false; let backtrace = self.error_at(index); errors.push(Error { error: err, @@ -342,6 +343,16 @@ impl ObligationForest { } } + if stalled { + // There's no need to perform marking, cycle processing and compression when nothing + // changed. + return Outcome { + completed: vec![], + errors: errors, + stalled: stalled, + }; + } + self.mark_as_waiting(); self.process_cycles(processor); @@ -366,8 +377,16 @@ impl ObligationForest { { let mut stack = self.scratch.take().unwrap(); - for node in 0..self.nodes.len() { - self.find_cycles_from_node(&mut stack, processor, node); + for index in 0..self.nodes.len() { + // For rustc-benchmarks/inflate-0.1.0 this state test is extremely + // hot and the state is almost always `Pending` or `Waiting`. It's + // a win to handle the no-op cases immediately to avoid the cost of + // the function call. + let state = self.nodes[index].state.get(); + match state { + NodeState::Waiting | NodeState::Pending | NodeState::Done | NodeState::Error => {}, + _ => self.find_cycles_from_node(&mut stack, processor, index), + } } self.scratch = Some(stack); @@ -465,7 +484,18 @@ impl ObligationForest { trace } - /// Marks all nodes that depend on a pending node as NodeState;:Waiting. + #[inline] + fn mark_neighbors_as_waiting_from(&self, node: &Node) { + if let Some(parent) = node.parent { + self.mark_as_waiting_from(&self.nodes[parent.get()]); + } + + for dependent in &node.dependents { + self.mark_as_waiting_from(&self.nodes[dependent.get()]); + } + } + + /// Marks all nodes that depend on a pending node as NodeState::Waiting. fn mark_as_waiting(&self) { for node in &self.nodes { if node.state.get() == NodeState::Waiting { @@ -475,27 +505,19 @@ impl ObligationForest { for node in &self.nodes { if node.state.get() == NodeState::Pending { - self.mark_as_waiting_from(node) + self.mark_neighbors_as_waiting_from(node); } } } fn mark_as_waiting_from(&self, node: &Node) { match node.state.get() { - NodeState::Pending | NodeState::Done => {}, NodeState::Waiting | NodeState::Error | NodeState::OnDfsStack => return, - NodeState::Success => { - node.state.set(NodeState::Waiting); - } - } - - if let Some(parent) = node.parent { - self.mark_as_waiting_from(&self.nodes[parent.get()]); + NodeState::Success => node.state.set(NodeState::Waiting), + NodeState::Pending | NodeState::Done => {}, } - for dependent in &node.dependents { - self.mark_as_waiting_from(&self.nodes[dependent.get()]); - } + self.mark_neighbors_as_waiting_from(node); } /// Compresses the vector, removing all popped nodes. This adjusts @@ -521,28 +543,28 @@ impl ObligationForest { // self.nodes[i..] are unchanged for i in 0..self.nodes.len() { match self.nodes[i].state.get() { + NodeState::Pending | NodeState::Waiting => { + if dead_nodes > 0 { + self.nodes.swap(i, i - dead_nodes); + node_rewrites[i] -= dead_nodes; + } + } NodeState::Done => { self.waiting_cache.remove(self.nodes[i].obligation.as_predicate()); // FIXME(HashMap): why can't I get my key back? self.done_cache.insert(self.nodes[i].obligation.as_predicate().clone()); + node_rewrites[i] = nodes_len; + dead_nodes += 1; } NodeState::Error => { // We *intentionally* remove the node from the cache at this point. Otherwise // tests must come up with a different type on every type error they // check against. self.waiting_cache.remove(self.nodes[i].obligation.as_predicate()); + node_rewrites[i] = nodes_len; + dead_nodes += 1; } - _ => {} - } - - if self.nodes[i].is_popped() { - node_rewrites[i] = nodes_len; - dead_nodes += 1; - } else { - if dead_nodes > 0 { - self.nodes.swap(i, i - dead_nodes); - node_rewrites[i] -= dead_nodes; - } + NodeState::OnDfsStack | NodeState::Success => unreachable!() } } @@ -622,12 +644,4 @@ impl Node { dependents: vec![], } } - - fn is_popped(&self) -> bool { - match self.state.get() { - NodeState::Pending | NodeState::Waiting => false, - NodeState::Error | NodeState::Done => true, - NodeState::OnDfsStack | NodeState::Success => unreachable!() - } - } } diff --git a/src/librustc_data_structures/snapshot_map/mod.rs b/src/librustc_data_structures/snapshot_map/mod.rs index b3989013d2..a4e6166032 100644 --- a/src/librustc_data_structures/snapshot_map/mod.rs +++ b/src/librustc_data_structures/snapshot_map/mod.rs @@ -11,6 +11,7 @@ use fnv::FnvHashMap; use std::hash::Hash; use std::ops; +use std::mem; #[cfg(test)] mod test; @@ -23,7 +24,7 @@ pub struct SnapshotMap } pub struct Snapshot { - len: usize + len: usize, } enum UndoLog { @@ -31,6 +32,7 @@ enum UndoLog { CommittedSnapshot, Inserted(K), Overwrite(K, V), + Noop, } impl SnapshotMap @@ -39,7 +41,7 @@ impl SnapshotMap pub fn new() -> Self { SnapshotMap { map: FnvHashMap(), - undo_log: vec![] + undo_log: vec![], } } @@ -68,9 +70,7 @@ impl SnapshotMap } true } - None => { - false - } + None => false, } } @@ -88,7 +88,7 @@ impl SnapshotMap assert!(snapshot.len < self.undo_log.len()); assert!(match self.undo_log[snapshot.len] { UndoLog::OpenSnapshot => true, - _ => false + _ => false, }); } @@ -102,29 +102,61 @@ impl SnapshotMap } } + pub fn partial_rollback(&mut self, + snapshot: &Snapshot, + should_revert_key: &F) + where F: Fn(&K) -> bool + { + self.assert_open_snapshot(snapshot); + for i in (snapshot.len + 1..self.undo_log.len()).rev() { + let reverse = match self.undo_log[i] { + UndoLog::OpenSnapshot => false, + UndoLog::CommittedSnapshot => false, + UndoLog::Noop => false, + UndoLog::Inserted(ref k) => should_revert_key(k), + UndoLog::Overwrite(ref k, _) => should_revert_key(k), + }; + + if reverse { + let entry = mem::replace(&mut self.undo_log[i], UndoLog::Noop); + self.reverse(entry); + } + } + } + pub fn rollback_to(&mut self, snapshot: Snapshot) { self.assert_open_snapshot(&snapshot); while self.undo_log.len() > snapshot.len + 1 { - match self.undo_log.pop().unwrap() { - UndoLog::OpenSnapshot => { - panic!("cannot rollback an uncommitted snapshot"); - } + let entry = self.undo_log.pop().unwrap(); + self.reverse(entry); + } + + let v = self.undo_log.pop().unwrap(); + assert!(match v { + UndoLog::OpenSnapshot => true, + _ => false, + }); + assert!(self.undo_log.len() == snapshot.len); + } - UndoLog::CommittedSnapshot => { } + fn reverse(&mut self, entry: UndoLog) { + match entry { + UndoLog::OpenSnapshot => { + panic!("cannot rollback an uncommitted snapshot"); + } - UndoLog::Inserted(key) => { - self.map.remove(&key); - } + UndoLog::CommittedSnapshot => {} - UndoLog::Overwrite(key, old_value) => { - self.map.insert(key, old_value); - } + UndoLog::Inserted(key) => { + self.map.remove(&key); } - } - let v = self.undo_log.pop().unwrap(); - assert!(match v { UndoLog::OpenSnapshot => true, _ => false }); - assert!(self.undo_log.len() == snapshot.len); + UndoLog::Overwrite(key, old_value) => { + self.map.insert(key, old_value); + } + + UndoLog::Noop => {} + } } } diff --git a/src/librustc_data_structures/unify/mod.rs b/src/librustc_data_structures/unify/mod.rs index 3feea3218d..1f4d09a922 100644 --- a/src/librustc_data_structures/unify/mod.rs +++ b/src/librustc_data_structures/unify/mod.rs @@ -27,7 +27,7 @@ mod tests; /// /// Clients are expected to provide implementations of this trait; you /// can see some examples in the `test` module. -pub trait UnifyKey : Copy + Clone + Debug + PartialEq { +pub trait UnifyKey: Copy + Clone + Debug + PartialEq { type Value: Clone + PartialEq + Debug; fn index(&self) -> u32; @@ -115,11 +115,7 @@ impl VarValue { } fn if_not_self(&self, key: K, self_key: K) -> Option { - if key == self_key { - None - } else { - Some(key) - } + if key == self_key { None } else { Some(key) } } } @@ -236,7 +232,8 @@ impl UnificationTable { new_rank: u32, old_root: VarValue, new_root: VarValue, - new_value: K::Value) -> K { + new_value: K::Value) + -> K { let old_root_key = old_root.key(); let new_root_key = new_root.key(); self.set(old_root_key, old_root.redirect(new_root_key)); @@ -306,7 +303,8 @@ impl<'tcx, K, V> UnificationTable let combined = { match (&node_a.value, &node_b.value) { (&None, &None) => None, - (&Some(ref v), &None) | (&None, &Some(ref v)) => Some(v.clone()), + (&Some(ref v), &None) | + (&None, &Some(ref v)) => Some(v.clone()), (&Some(ref v1), &Some(ref v2)) => { if *v1 != *v2 { return Err((v1.clone(), v2.clone())); diff --git a/src/librustc_driver/Cargo.toml b/src/librustc_driver/Cargo.toml index 772d83eb2c..99d3e155e8 100644 --- a/src/librustc_driver/Cargo.toml +++ b/src/librustc_driver/Cargo.toml @@ -13,25 +13,26 @@ arena = { path = "../libarena" } flate = { path = "../libflate" } graphviz = { path = "../libgraphviz" } log = { path = "../liblog" } +proc_macro_plugin = { path = "../libproc_macro_plugin" } rustc = { path = "../librustc" } rustc_back = { path = "../librustc_back" } rustc_borrowck = { path = "../librustc_borrowck" } rustc_const_eval = { path = "../librustc_const_eval" } +rustc_data_structures = { path = "../librustc_data_structures" } rustc_errors = { path = "../librustc_errors" } +rustc_incremental = { path = "../librustc_incremental" } rustc_lint = { path = "../librustc_lint" } rustc_llvm = { path = "../librustc_llvm" } +rustc_metadata = { path = "../librustc_metadata" } rustc_mir = { path = "../librustc_mir" } -rustc_plugin = { path = "../librustc_plugin" } rustc_passes = { path = "../librustc_passes" } +rustc_plugin = { path = "../librustc_plugin" } rustc_privacy = { path = "../librustc_privacy" } -rustc_incremental = { path = "../librustc_incremental" } rustc_resolve = { path = "../librustc_resolve" } rustc_save_analysis = { path = "../librustc_save_analysis" } rustc_trans = { path = "../librustc_trans" } rustc_typeck = { path = "../librustc_typeck" } -rustc_metadata = { path = "../librustc_metadata" } serialize = { path = "../libserialize" } syntax = { path = "../libsyntax" } syntax_ext = { path = "../libsyntax_ext" } syntax_pos = { path = "../libsyntax_pos" } -proc_macro = { path = "../libproc_macro" } diff --git a/src/librustc_driver/driver.rs b/src/librustc_driver/driver.rs index 9d5dce7ad0..d839184956 100644 --- a/src/librustc_driver/driver.rs +++ b/src/librustc_driver/driver.rs @@ -12,8 +12,10 @@ use rustc::hir; use rustc::hir::{map as hir_map, FreevarMap, TraitMap}; use rustc::hir::def::DefMap; use rustc::hir::lowering::lower_crate; +use rustc_data_structures::blake2b::Blake2bHasher; +use rustc_data_structures::fmt_wrap::FmtWrap; +use rustc::ty::util::ArchIndependentHasher; use rustc_mir as mir; -use rustc::mir::mir_map::MirMap; use rustc::session::{Session, CompileResult, compile_result_from_err_count}; use rustc::session::config::{self, Input, OutputFilenames, OutputType, OutputTypes}; @@ -24,7 +26,6 @@ use rustc::middle::privacy::AccessLevels; use rustc::ty::{self, TyCtxt}; use rustc::util::common::time; use rustc::util::nodemap::NodeSet; -use rustc_back::sha2::{Sha256, Digest}; use rustc_borrowck as borrowck; use rustc_incremental::{self, IncrementalHashesMap}; use rustc_resolve::{MakeGlobMap, Resolver}; @@ -36,7 +37,8 @@ use rustc_typeck as typeck; use rustc_privacy; use rustc_plugin::registry::Registry; use rustc_plugin as plugin; -use rustc_passes::{ast_validation, no_asm, loops, consts, rvalues, static_recursion}; +use rustc_passes::{ast_validation, no_asm, loops, consts, rvalues, + static_recursion, hir_stats}; use rustc_const_eval::check_match; use super::Compilation; @@ -68,7 +70,6 @@ pub struct Resolutions { pub fn compile_input(sess: &Session, cstore: &CStore, - cfg: ast::CrateConfig, input: &Input, outdir: &Option, output: &Option, @@ -92,7 +93,7 @@ pub fn compile_input(sess: &Session, // large chunks of memory alive and we want to free them as soon as // possible to keep the peak memory usage low let (outputs, trans) = { - let krate = match phase_1_parse_input(sess, cfg, input) { + let krate = match phase_1_parse_input(sess, input) { Ok(krate) => krate, Err(mut parse_error) => { parse_error.emit(); @@ -175,7 +176,7 @@ pub fn compile_input(sess: &Session, resolutions, &arenas, &crate_name, - |tcx, mir_map, analysis, incremental_hashes_map, result| { + |tcx, analysis, incremental_hashes_map, result| { { // Eventually, we will want to track plugins. let _ignore = tcx.dep_graph.in_ignore(); @@ -187,7 +188,6 @@ pub fn compile_input(sess: &Session, opt_crate, tcx.map.krate(), &analysis, - mir_map.as_ref(), tcx, &crate_name); (control.after_analysis.callback)(&mut state); @@ -203,10 +203,7 @@ pub fn compile_input(sess: &Session, println!("Pre-trans"); tcx.print_debug_stats(); } - let trans = phase_4_translate_to_llvm(tcx, - mir_map.unwrap(), - analysis, - &incremental_hashes_map); + let trans = phase_4_translate_to_llvm(tcx, analysis, &incremental_hashes_map); if log_enabled!(::log::INFO) { println!("Post-trans"); @@ -348,7 +345,6 @@ pub struct CompileState<'a, 'b, 'ast: 'a, 'tcx: 'b> where 'ast: 'tcx { pub hir_crate: Option<&'a hir::Crate>, pub ast_map: Option<&'a hir_map::Map<'ast>>, pub resolutions: Option<&'a Resolutions>, - pub mir_map: Option<&'b MirMap<'tcx>>, pub analysis: Option<&'a ty::CrateAnalysis<'a>>, pub tcx: Option>, pub trans: Option<&'a trans::CrateTranslation>, @@ -375,7 +371,6 @@ impl<'a, 'b, 'ast, 'tcx> CompileState<'a, 'b, 'ast, 'tcx> { ast_map: None, resolutions: None, analysis: None, - mir_map: None, tcx: None, trans: None, } @@ -449,13 +444,11 @@ impl<'a, 'b, 'ast, 'tcx> CompileState<'a, 'b, 'ast, 'tcx> { krate: Option<&'a ast::Crate>, hir_crate: &'a hir::Crate, analysis: &'a ty::CrateAnalysis<'a>, - mir_map: Option<&'b MirMap<'tcx>>, tcx: TyCtxt<'b, 'tcx, 'tcx>, crate_name: &'a str) -> CompileState<'a, 'b, 'ast, 'tcx> { CompileState { analysis: Some(analysis), - mir_map: mir_map, tcx: Some(tcx), expanded_crate: krate, hir_crate: Some(hir_crate), @@ -491,23 +484,17 @@ impl<'a, 'b, 'ast, 'tcx> CompileState<'a, 'b, 'ast, 'tcx> { } } -pub fn phase_1_parse_input<'a>(sess: &'a Session, - cfg: ast::CrateConfig, - input: &Input) - -> PResult<'a, ast::Crate> { +pub fn phase_1_parse_input<'a>(sess: &'a Session, input: &Input) -> PResult<'a, ast::Crate> { let continue_after_error = sess.opts.debugging_opts.continue_parse_after_error; sess.diagnostic().set_continue_after_error(continue_after_error); let krate = time(sess.time_passes(), "parsing", || { match *input { Input::File(ref file) => { - parse::parse_crate_from_file(file, cfg.clone(), &sess.parse_sess) + parse::parse_crate_from_file(file, &sess.parse_sess) } Input::Str { ref input, ref name } => { - parse::parse_crate_from_source_str(name.clone(), - input.clone(), - cfg.clone(), - &sess.parse_sess) + parse::parse_crate_from_source_str(name.clone(), input.clone(), &sess.parse_sess) } } })?; @@ -527,6 +514,10 @@ pub fn phase_1_parse_input<'a>(sess: &'a Session, syntax::show_span::run(sess.diagnostic(), s, &krate); } + if sess.opts.debugging_opts.hir_stats { + hir_stats::print_ast_stats(&krate, "PRE EXPANSION AST STATS"); + } + Ok(krate) } @@ -639,11 +630,18 @@ pub fn phase_2_configure_and_expand<'a, F>(sess: &Session, } sess.track_errors(|| sess.lint_store.borrow_mut().process_command_line(sess))?; - let mut crate_loader = CrateLoader::new(sess, &cstore, &krate, crate_name); + // Currently, we ignore the name resolution data structures for the purposes of dependency + // tracking. Instead we will run name resolution and include its output in the hash of each + // item, much like we do for macro expansion. In other words, the hash reflects not just + // its contents but the results of name resolution on those contents. Hopefully we'll push + // this back at some point. + let _ignore = sess.dep_graph.in_ignore(); + let mut crate_loader = CrateLoader::new(sess, &cstore, crate_name); + crate_loader.preprocess(&krate); let resolver_arenas = Resolver::arenas(); let mut resolver = Resolver::new(sess, &krate, make_glob_map, &mut crate_loader, &resolver_arenas); - syntax_ext::register_builtins(&mut resolver, sess.features.borrow().quote); + syntax_ext::register_builtins(&mut resolver, syntax_exts, sess.features.borrow().quote); krate = time(time_passes, "expansion", || { // Windows dlls do not have rpaths, so they don't know how to find their @@ -679,12 +677,18 @@ pub fn phase_2_configure_and_expand<'a, F>(sess: &Session, should_test: sess.opts.test, ..syntax::ext::expand::ExpansionConfig::default(crate_name.to_string()) }; - let mut ecx = ExtCtxt::new(&sess.parse_sess, krate.config.clone(), cfg, &mut resolver); - let ret = syntax::ext::expand::expand_crate(&mut ecx, syntax_exts, krate); + let mut ecx = ExtCtxt::new(&sess.parse_sess, cfg, &mut resolver); + let err_count = ecx.parse_sess.span_diagnostic.err_count(); + + let krate = ecx.monotonic_expander().expand_crate(krate); + + if ecx.parse_sess.span_diagnostic.err_count() - ecx.resolve_err_count > err_count { + ecx.parse_sess.span_diagnostic.abort_if_errors(); + } if cfg!(windows) { env::set_var("PATH", &old_path); } - ret + krate }); krate.exported_macros = mem::replace(&mut resolver.exported_macros, Vec::new()); @@ -697,23 +701,32 @@ pub fn phase_2_configure_and_expand<'a, F>(sess: &Session, sess.diagnostic()) }); - krate = time(time_passes, "maybe creating a macro crate", || { - let crate_types = sess.crate_types.borrow(); - let is_rustc_macro_crate = crate_types.contains(&config::CrateTypeRustcMacro); - let num_crate_types = crate_types.len(); - syntax_ext::rustc_macro_registrar::modify(&sess.parse_sess, - &mut resolver, - krate, - is_rustc_macro_crate, - num_crate_types, - sess.diagnostic(), - &sess.features.borrow()) - }); + // If we're in rustdoc we're always compiling as an rlib, but that'll trip a + // bunch of checks in the `modify` function below. For now just skip this + // step entirely if we're rustdoc as it's not too useful anyway. + if !sess.opts.actually_rustdoc { + krate = time(time_passes, "maybe creating a macro crate", || { + let crate_types = sess.crate_types.borrow(); + let num_crate_types = crate_types.len(); + let is_proc_macro_crate = crate_types.contains(&config::CrateTypeProcMacro); + syntax_ext::proc_macro_registrar::modify(&sess.parse_sess, + &mut resolver, + krate, + is_proc_macro_crate, + num_crate_types, + sess.diagnostic(), + &sess.features.borrow()) + }); + } if sess.opts.debugging_opts.input_stats { println!("Post-expansion node count: {}", count_nodes(&krate)); } + if sess.opts.debugging_opts.hir_stats { + hir_stats::print_ast_stats(&krate, "POST EXPANSION AST STATS"); + } + if sess.opts.debugging_opts.ast_json { println!("{}", json::as_json(&krate)); } @@ -733,9 +746,6 @@ pub fn phase_2_configure_and_expand<'a, F>(sess: &Session, }) })?; - // Collect defintions for def ids. - time(sess.time_passes(), "collecting defs", || resolver.definitions.collect(&krate)); - time(sess.time_passes(), "early lint checks", || lint::check_ast_crate(sess, &krate)); @@ -745,13 +755,6 @@ pub fn phase_2_configure_and_expand<'a, F>(sess: &Session, || ast_validation::check_crate(sess, &krate)); time(sess.time_passes(), "name resolution", || -> CompileResult { - // Currently, we ignore the name resolution data structures for the purposes of dependency - // tracking. Instead we will run name resolution and include its output in the hash of each - // item, much like we do for macro expansion. In other words, the hash reflects not just - // its contents but the results of name resolution on those contents. Hopefully we'll push - // this back at some point. - let _ignore = sess.dep_graph.in_ignore(); - resolver.build_reduced_graph(&krate); resolver.resolve_imports(); // Since import resolution will eventually happen in expansion, @@ -764,7 +767,13 @@ pub fn phase_2_configure_and_expand<'a, F>(sess: &Session, // Lower ast -> hir. let hir_forest = time(sess.time_passes(), "lowering ast -> hir", || { - hir_map::Forest::new(lower_crate(sess, &krate, &mut resolver), &sess.dep_graph) + let hir_crate = lower_crate(sess, &krate, &mut resolver); + + if sess.opts.debugging_opts.hir_stats { + hir_stats::print_hir_stats(&hir_crate); + } + + hir_map::Forest::new(hir_crate, &sess.dep_graph) }); // Discard hygiene data, which isn't required past lowering to HIR. @@ -804,17 +813,16 @@ pub fn phase_3_run_analysis_passes<'tcx, F, R>(sess: &'tcx Session, f: F) -> Result where F: for<'a> FnOnce(TyCtxt<'a, 'tcx, 'tcx>, - Option>, ty::CrateAnalysis, IncrementalHashesMap, CompileResult) -> R { macro_rules! try_with_f { - ($e: expr, ($t: expr, $m: expr, $a: expr, $h: expr)) => { + ($e: expr, ($t: expr, $a: expr, $h: expr)) => { match $e { Ok(x) => x, Err(x) => { - f($t, $m, $a, $h, Err(x)); + f($t, $a, $h, Err(x)); return Err(x); } } @@ -880,7 +888,7 @@ pub fn phase_3_run_analysis_passes<'tcx, F, R>(sess: &'tcx Session, || rustc_incremental::load_dep_graph(tcx, &incremental_hashes_map)); // passes are timed inside typeck - try_with_f!(typeck::check_crate(tcx), (tcx, None, analysis, incremental_hashes_map)); + try_with_f!(typeck::check_crate(tcx), (tcx, analysis, incremental_hashes_map)); time(time_passes, "const checking", @@ -920,28 +928,30 @@ pub fn phase_3_run_analysis_passes<'tcx, F, R>(sess: &'tcx Session, "rvalue checking", || rvalues::check_crate(tcx)); - let mut mir_map = - time(time_passes, - "MIR dump", - || mir::mir_map::build_mir_for_crate(tcx)); + time(time_passes, + "MIR dump", + || mir::mir_map::build_mir_for_crate(tcx)); - time(time_passes, "MIR passes", || { + time(time_passes, "MIR cleanup and validation", || { let mut passes = sess.mir_passes.borrow_mut(); - // Push all the built-in passes. + // Push all the built-in validation passes. + // NB: if you’re adding an *optimisation* it ought to go to another set of passes + // in stage 4 below. passes.push_hook(box mir::transform::dump_mir::DumpMir); - passes.push_pass(box mir::transform::simplify_cfg::SimplifyCfg::new("initial")); - passes.push_pass(box mir::transform::qualify_consts::QualifyAndPromoteConstants); + passes.push_pass(box mir::transform::simplify::SimplifyCfg::new("initial")); + passes.push_pass( + box mir::transform::qualify_consts::QualifyAndPromoteConstants::default()); passes.push_pass(box mir::transform::type_check::TypeckMir); passes.push_pass( box mir::transform::simplify_branches::SimplifyBranches::new("initial")); - passes.push_pass(box mir::transform::simplify_cfg::SimplifyCfg::new("qualify-consts")); + passes.push_pass(box mir::transform::simplify::SimplifyCfg::new("qualify-consts")); // And run everything. - passes.run_passes(tcx, &mut mir_map); + passes.run_passes(tcx); }); time(time_passes, "borrow checking", - || borrowck::check_crate(tcx, &mir_map)); + || borrowck::check_crate(tcx)); // Avoid overwhelming user with errors if type checking failed. // I'm not sure how helpful this is, to be honest, but it avoids @@ -950,11 +960,7 @@ pub fn phase_3_run_analysis_passes<'tcx, F, R>(sess: &'tcx Session, // lint warnings and so on -- kindck used to do this abort, but // kindck is gone now). -nmatsakis if sess.err_count() > 0 { - return Ok(f(tcx, - Some(mir_map), - analysis, - incremental_hashes_map, - Err(sess.err_count()))); + return Ok(f(tcx, analysis, incremental_hashes_map, Err(sess.err_count()))); } analysis.reachable = @@ -982,20 +988,15 @@ pub fn phase_3_run_analysis_passes<'tcx, F, R>(sess: &'tcx Session, // The above three passes generate errors w/o aborting if sess.err_count() > 0 { - return Ok(f(tcx, - Some(mir_map), - analysis, - incremental_hashes_map, - Err(sess.err_count()))); + return Ok(f(tcx, analysis, incremental_hashes_map, Err(sess.err_count()))); } - Ok(f(tcx, Some(mir_map), analysis, incremental_hashes_map, Ok(()))) + Ok(f(tcx, analysis, incremental_hashes_map, Ok(()))) }) } /// Run the translation phase to LLVM, after which the AST and analysis can pub fn phase_4_translate_to_llvm<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, - mut mir_map: MirMap<'tcx>, analysis: ty::CrateAnalysis, incremental_hashes_map: &IncrementalHashesMap) -> trans::CrateTranslation { @@ -1005,13 +1006,13 @@ pub fn phase_4_translate_to_llvm<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, "resolving dependency formats", || dependency_format::calculate(&tcx.sess)); - // Run the passes that transform the MIR into a more suitable for translation - // to LLVM code. - time(time_passes, "Prepare MIR codegen passes", || { + // Run the passes that transform the MIR into a more suitable form for translation to LLVM + // code. + time(time_passes, "MIR optimisations", || { let mut passes = ::rustc::mir::transform::Passes::new(); passes.push_hook(box mir::transform::dump_mir::DumpMir); passes.push_pass(box mir::transform::no_landing_pads::NoLandingPads); - passes.push_pass(box mir::transform::simplify_cfg::SimplifyCfg::new("no-landing-pads")); + passes.push_pass(box mir::transform::simplify::SimplifyCfg::new("no-landing-pads")); // From here on out, regions are gone. passes.push_pass(box mir::transform::erase_regions::EraseRegions); @@ -1019,23 +1020,24 @@ pub fn phase_4_translate_to_llvm<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, passes.push_pass(box mir::transform::add_call_guards::AddCallGuards); passes.push_pass(box borrowck::ElaborateDrops); passes.push_pass(box mir::transform::no_landing_pads::NoLandingPads); - passes.push_pass(box mir::transform::simplify_cfg::SimplifyCfg::new("elaborate-drops")); + passes.push_pass(box mir::transform::simplify::SimplifyCfg::new("elaborate-drops")); // No lifetime analysis based on borrowing can be done from here on out. passes.push_pass(box mir::transform::instcombine::InstCombine::new()); passes.push_pass(box mir::transform::deaggregator::Deaggregator); passes.push_pass(box mir::transform::copy_prop::CopyPropagation); + passes.push_pass(box mir::transform::simplify::SimplifyLocals); passes.push_pass(box mir::transform::add_call_guards::AddCallGuards); passes.push_pass(box mir::transform::dump_mir::Marker("PreTrans")); - passes.run_passes(tcx, &mut mir_map); + passes.run_passes(tcx); }); let translation = time(time_passes, "translation", - move || trans::trans_crate(tcx, &mir_map, analysis, &incremental_hashes_map)); + move || trans::trans_crate(tcx, analysis, &incremental_hashes_map)); time(time_passes, "assert dep graph", @@ -1180,8 +1182,8 @@ pub fn collect_crate_types(session: &Session, attrs: &[ast::Attribute]) -> Vec { Some(config::CrateTypeStaticlib) } - Some(ref n) if *n == "rustc-macro" => { - Some(config::CrateTypeRustcMacro) + Some(ref n) if *n == "proc-macro" => { + Some(config::CrateTypeProcMacro) } Some(ref n) if *n == "bin" => Some(config::CrateTypeExecutable), Some(_) => { @@ -1239,7 +1241,16 @@ pub fn collect_crate_types(session: &Session, attrs: &[ast::Attribute]) -> Vec String { - let mut hasher = Sha256::new(); + use std::hash::Hasher; + + // The crate_disambiguator is a 128 bit hash. The disambiguator is fed + // into various other hashes quite a bit (symbol hashes, incr. comp. hashes, + // debuginfo type IDs, etc), so we don't want it to be too wide. 128 bits + // should still be safe enough to avoid collisions in practice. + // FIXME(mw): It seems that the crate_disambiguator is used everywhere as + // a hex-string instead of raw bytes. We should really use the + // smaller representation. + let mut hasher = ArchIndependentHasher::new(Blake2bHasher::new(128 / 8, &[])); let mut metadata = session.opts.cg.metadata.clone(); // We don't want the crate_disambiguator to dependent on the order @@ -1248,24 +1259,23 @@ pub fn compute_crate_disambiguator(session: &Session) -> String { // Every distinct -C metadata value is only incorporated once: metadata.dedup(); - hasher.input_str("metadata"); + hasher.write(b"metadata"); for s in &metadata { // Also incorporate the length of a metadata string, so that we generate // different values for `-Cmetadata=ab -Cmetadata=c` and // `-Cmetadata=a -Cmetadata=bc` - hasher.input_str(&format!("{}", s.len())[..]); - hasher.input_str(&s[..]); + hasher.write_usize(s.len()); + hasher.write(s.as_bytes()); } - let mut hash = hasher.result_str(); + let mut hash_state = hasher.into_inner(); + let hash_bytes = hash_state.finalize(); // If this is an executable, add a special suffix, so that we don't get // symbol conflicts when linking against a library of the same name. - if session.crate_types.borrow().contains(&config::CrateTypeExecutable) { - hash.push_str("-exe"); - } + let is_exe = session.crate_types.borrow().contains(&config::CrateTypeExecutable); - hash + format!("{:x}{}", FmtWrap(hash_bytes), if is_exe { "-exe" } else {""}) } pub fn build_output_filenames(input: &Input, diff --git a/src/librustc_driver/lib.rs b/src/librustc_driver/lib.rs index dfc4bcebd3..6ddbce7dc7 100644 --- a/src/librustc_driver/lib.rs +++ b/src/librustc_driver/lib.rs @@ -24,7 +24,7 @@ #![cfg_attr(not(stage0), deny(warnings))] #![feature(box_syntax)] -#![feature(dotdot_in_tuple_patterns)] +#![cfg_attr(stage0, feature(dotdot_in_tuple_patterns))] #![feature(libc)] #![feature(quote)] #![feature(rustc_diagnostic_macros)] @@ -42,6 +42,7 @@ extern crate rustc; extern crate rustc_back; extern crate rustc_borrowck; extern crate rustc_const_eval; +extern crate rustc_data_structures; extern crate rustc_errors as errors; extern crate rustc_passes; extern crate rustc_lint; @@ -74,9 +75,10 @@ use rustc::dep_graph::DepGraph; use rustc::session::{self, config, Session, build_session, CompileResult}; use rustc::session::config::{Input, PrintRequest, OutputType, ErrorOutputType}; use rustc::session::config::nightly_options; +use rustc::session::early_error; use rustc::lint::Lint; use rustc::lint; -use rustc_metadata::loader; +use rustc_metadata::locator; use rustc_metadata::cstore::CStore; use rustc::util::common::time; @@ -93,8 +95,6 @@ use std::str; use std::sync::{Arc, Mutex}; use std::thread; -use rustc::session::early_error; - use syntax::{ast, json}; use syntax::codemap::{CodeMap, FileLoader, RealFileLoader}; use syntax::feature_gate::{GatedCfg, UnstableFeatures}; @@ -131,17 +131,18 @@ pub fn abort_on_err(result: Result, sess: &Session) -> T { } } -pub fn run(args: Vec) -> isize { +pub fn run(run_compiler: F) -> isize + where F: FnOnce() -> (CompileResult, Option) + Send + 'static +{ monitor(move || { - let (result, session) = run_compiler(&args, &mut RustcDefaultCalls); + let (result, session) = run_compiler(); if let Err(err_count) = result { if err_count > 0 { match session { Some(sess) => sess.fatal(&abort_msg(err_count)), None => { let emitter = - errors::emitter::EmitterWriter::stderr(errors::ColorConfig::Auto, - None); + errors::emitter::EmitterWriter::stderr(errors::ColorConfig::Auto, None); let handler = errors::Handler::with_emitter(true, false, Box::new(emitter)); handler.emit(&MultiSpan::new(), &abort_msg(err_count), @@ -155,20 +156,15 @@ pub fn run(args: Vec) -> isize { 0 } -pub fn run_compiler<'a>(args: &[String], - callbacks: &mut CompilerCalls<'a>) - -> (CompileResult, Option) { - run_compiler_with_file_loader(args, callbacks, box RealFileLoader) -} - // Parse args and run the compiler. This is the primary entry point for rustc. // See comments on CompilerCalls below for details about the callbacks argument. // The FileLoader provides a way to load files from sources other than the file system. -pub fn run_compiler_with_file_loader<'a, L>(args: &[String], - callbacks: &mut CompilerCalls<'a>, - loader: Box) - -> (CompileResult, Option) - where L: FileLoader + 'static { +pub fn run_compiler<'a>(args: &[String], + callbacks: &mut CompilerCalls<'a>, + file_loader: Option>, + emitter_dest: Option>) + -> (CompileResult, Option) +{ macro_rules! do_or_return {($expr: expr, $sess: expr) => { match $expr { Compilation::Stop => return (Ok(()), $sess), @@ -207,24 +203,23 @@ pub fn run_compiler_with_file_loader<'a, L>(args: &[String], let dep_graph = DepGraph::new(sopts.build_dep_graph()); let cstore = Rc::new(CStore::new(&dep_graph)); + + let loader = file_loader.unwrap_or(box RealFileLoader); let codemap = Rc::new(CodeMap::with_file_loader(loader)); - let sess = session::build_session_with_codemap(sopts, - &dep_graph, - input_file_path, - descriptions, - cstore.clone(), - codemap); + let mut sess = session::build_session_with_codemap( + sopts, &dep_graph, input_file_path, descriptions, cstore.clone(), codemap, emitter_dest, + ); rustc_lint::register_builtins(&mut sess.lint_store.borrow_mut(), Some(&sess)); + let mut cfg = config::build_configuration(&sess, cfg); target_features::add_configuration(&mut cfg, &sess); + sess.parse_sess.config = cfg; - do_or_return!(callbacks.late_callback(&matches, &sess, &cfg, &input, &odir, &ofile), - Some(sess)); + do_or_return!(callbacks.late_callback(&matches, &sess, &input, &odir, &ofile), Some(sess)); let plugins = sess.opts.debugging_opts.extra_plugins.clone(); let control = callbacks.build_controller(&sess, &matches); - (driver::compile_input(&sess, &cstore, cfg, &input, &odir, &ofile, - Some(plugins), &control), + (driver::compile_input(&sess, &cstore, &input, &odir, &ofile, Some(plugins), &control), Some(sess)) } @@ -312,7 +307,6 @@ pub trait CompilerCalls<'a> { fn late_callback(&mut self, _: &getopts::Matches, _: &Session, - _: &ast::CrateConfig, _: &Input, _: &Option, _: &Option) @@ -441,7 +435,7 @@ impl<'a> CompilerCalls<'a> for RustcDefaultCalls { } let dep_graph = DepGraph::new(sopts.build_dep_graph()); let cstore = Rc::new(CStore::new(&dep_graph)); - let sess = build_session(sopts.clone(), + let mut sess = build_session(sopts.clone(), &dep_graph, None, descriptions.clone(), @@ -449,11 +443,10 @@ impl<'a> CompilerCalls<'a> for RustcDefaultCalls { rustc_lint::register_builtins(&mut sess.lint_store.borrow_mut(), Some(&sess)); let mut cfg = config::build_configuration(&sess, cfg.clone()); target_features::add_configuration(&mut cfg, &sess); - let should_stop = RustcDefaultCalls::print_crate_info(&sess, - &cfg, - None, - odir, - ofile); + sess.parse_sess.config = cfg; + let should_stop = + RustcDefaultCalls::print_crate_info(&sess, None, odir, ofile); + if should_stop == Compilation::Stop { return None; } @@ -469,12 +462,11 @@ impl<'a> CompilerCalls<'a> for RustcDefaultCalls { fn late_callback(&mut self, matches: &getopts::Matches, sess: &Session, - cfg: &ast::CrateConfig, input: &Input, odir: &Option, ofile: &Option) -> Compilation { - RustcDefaultCalls::print_crate_info(sess, cfg, Some(input), odir, ofile) + RustcDefaultCalls::print_crate_info(sess, Some(input), odir, ofile) .and_then(|| RustcDefaultCalls::list_metadata(sess, matches, input)) } @@ -580,8 +572,7 @@ impl RustcDefaultCalls { &Input::File(ref ifile) => { let path = &(*ifile); let mut v = Vec::new(); - loader::list_file_metadata(&sess.target.target, path, &mut v) - .unwrap(); + locator::list_file_metadata(&sess.target.target, path, &mut v).unwrap(); println!("{}", String::from_utf8(v).unwrap()); } &Input::Str { .. } => { @@ -596,7 +587,6 @@ impl RustcDefaultCalls { fn print_crate_info(sess: &Session, - cfg: &ast::CrateConfig, input: Option<&Input>, odir: &Option, ofile: &Option) @@ -652,8 +642,8 @@ impl RustcDefaultCalls { let allow_unstable_cfg = UnstableFeatures::from_environment() .is_nightly_build(); - for cfg in cfg { - if !allow_unstable_cfg && GatedCfg::gate(&*cfg).is_some() { + for cfg in &sess.parse_sess.config { + if !allow_unstable_cfg && GatedCfg::gate(cfg).is_some() { continue; } @@ -731,6 +721,10 @@ pub fn version(binary: &str, matches: &getopts::Matches) { println!("commit-date: {}", unw(commit_date_str())); println!("host: {}", config::host_triple()); println!("release: {}", unw(release_str())); + unsafe { + println!("LLVM version: {}.{}", + llvm::LLVMRustVersionMajor(), llvm::LLVMRustVersionMinor()); + } } } @@ -1035,13 +1029,10 @@ pub fn handle_options(args: &[String]) -> Option { fn parse_crate_attrs<'a>(sess: &'a Session, input: &Input) -> PResult<'a, Vec> { match *input { Input::File(ref ifile) => { - parse::parse_crate_attrs_from_file(ifile, Vec::new(), &sess.parse_sess) + parse::parse_crate_attrs_from_file(ifile, &sess.parse_sess) } Input::Str { ref name, ref input } => { - parse::parse_crate_attrs_from_source_str(name.clone(), - input.clone(), - Vec::new(), - &sess.parse_sess) + parse::parse_crate_attrs_from_source_str(name.clone(), input.clone(), &sess.parse_sess) } } } @@ -1077,7 +1068,7 @@ pub fn monitor(f: F) { } let thread = cfg.spawn(move || { - io::set_panic(box err); + io::set_panic(Some(box err)); f() }); @@ -1112,7 +1103,7 @@ pub fn monitor(f: F) { errors::Level::Note); } - println!("{}", str::from_utf8(&data.lock().unwrap()).unwrap()); + writeln!(io::stderr(), "{}", str::from_utf8(&data.lock().unwrap()).unwrap()).unwrap(); } exit_on_err(); @@ -1123,7 +1114,7 @@ fn exit_on_err() -> ! { // Panic so the process returns a failure code, but don't pollute the // output with some unnecessary panic messages, we've already // printed everything that we needed to. - io::set_panic(box io::sink()); + io::set_panic(Some(box io::sink())); panic!(); } @@ -1144,6 +1135,9 @@ pub fn diagnostics_registry() -> errors::registry::Registry { } pub fn main() { - let result = run(env::args().collect()); + let result = run(|| run_compiler(&env::args().collect::>(), + &mut RustcDefaultCalls, + None, + None)); process::exit(result as i32); } diff --git a/src/librustc_driver/pretty.rs b/src/librustc_driver/pretty.rs index 215287f843..b4ab9da92e 100644 --- a/src/librustc_driver/pretty.rs +++ b/src/librustc_driver/pretty.rs @@ -52,8 +52,6 @@ use rustc::hir::map::{blocks, NodePrinter}; use rustc::hir; use rustc::hir::print as pprust_hir; -use rustc::mir::mir_map::MirMap; - #[derive(Copy, Clone, PartialEq, Debug)] pub enum PpSourceMode { PpmNormal, @@ -103,8 +101,8 @@ impl PpMode { pub fn needs_analysis(&self) -> bool { match *self { - PpmMir | PpmMirCFG | PpmFlowGraph(_) => true, - _ => false, + PpmMir | PpmMirCFG | PpmFlowGraph(_) => true, + _ => false, } } } @@ -234,15 +232,12 @@ impl PpSourceMode { resolutions.clone(), arenas, id, - |tcx, _, _, _, _| { - let annotation = TypedAnnotation { - tcx: tcx, - }; + |tcx, _, _, _| { + let annotation = TypedAnnotation { tcx: tcx }; let _ignore = tcx.dep_graph.in_ignore(); - f(&annotation, - payload, - ast_map.forest.krate()) - }), sess) + f(&annotation, payload, ast_map.forest.krate()) + }), + sess) } _ => panic!("Should use call_with_pp_support"), } @@ -283,9 +278,11 @@ trait HirPrinterSupport<'ast>: pprust_hir::PpAnn { /// Computes an user-readable representation of a path, if possible. fn node_path(&self, id: ast::NodeId) -> Option { self.ast_map().and_then(|map| map.def_path_from_id(id)).map(|path| { - path.data.into_iter().map(|elem| { - elem.data.to_string() - }).collect::>().join("::") + path.data + .into_iter() + .map(|elem| elem.data.to_string()) + .collect::>() + .join("::") }) } } @@ -354,7 +351,8 @@ impl<'ast> pprust::PpAnn for IdentifiedAnnotation<'ast> { } fn post(&self, s: &mut pprust::State, node: pprust::AnnNode) -> io::Result<()> { match node { - pprust::NodeIdent(_) | pprust::NodeName(_) => Ok(()), + pprust::NodeIdent(_) | + pprust::NodeName(_) => Ok(()), pprust::NodeItem(item) => { pp::space(&mut s.s)?; @@ -503,7 +501,7 @@ impl<'a, 'tcx> pprust_hir::PpAnn for TypedAnnotation<'a, 'tcx> { pp::space(&mut s.s)?; pp::word(&mut s.s, "as")?; pp::space(&mut s.s)?; - pp::word(&mut s.s, &self.tcx.expr_ty(expr).to_string())?; + pp::word(&mut s.s, &self.tcx.tables().expr_ty(expr).to_string())?; s.pclose() } _ => Ok(()), @@ -619,15 +617,14 @@ impl ReplaceBodyWithLoop { impl fold::Folder for ReplaceBodyWithLoop { fn fold_item_kind(&mut self, i: ast::ItemKind) -> ast::ItemKind { match i { - ast::ItemKind::Static(..) | ast::ItemKind::Const(..) => { + ast::ItemKind::Static(..) | + ast::ItemKind::Const(..) => { self.within_static_or_const = true; let ret = fold::noop_fold_item_kind(i, self); self.within_static_or_const = false; return ret; } - _ => { - fold::noop_fold_item_kind(i, self) - } + _ => fold::noop_fold_item_kind(i, self), } } @@ -658,11 +655,15 @@ impl fold::Folder for ReplaceBodyWithLoop { fn fold_block(&mut self, b: P) -> P { fn expr_to_block(rules: ast::BlockCheckMode, e: Option>) -> P { P(ast::Block { - stmts: e.map(|e| ast::Stmt { - id: ast::DUMMY_NODE_ID, - span: e.span, - node: ast::StmtKind::Expr(e), - }).into_iter().collect(), + stmts: e.map(|e| { + ast::Stmt { + id: ast::DUMMY_NODE_ID, + span: e.span, + node: ast::StmtKind::Expr(e), + } + }) + .into_iter() + .collect(), rules: rules, id: ast::DUMMY_NODE_ID, span: syntax_pos::DUMMY_SP, @@ -695,7 +696,6 @@ impl fold::Folder for ReplaceBodyWithLoop { fn print_flowgraph<'a, 'tcx, W: Write>(variants: Vec, tcx: TyCtxt<'a, 'tcx, 'tcx>, - mir_map: Option<&MirMap<'tcx>>, code: blocks::Code, mode: PpFlowGraphMode, mut out: W) @@ -724,10 +724,7 @@ fn print_flowgraph<'a, 'tcx, W: Write>(variants: Vec, } blocks::FnLikeCode(fn_like) => { let (bccx, analysis_data) = - borrowck::build_borrowck_dataflow_data_for_fn(tcx, - mir_map, - fn_like.to_fn_parts(), - &cfg); + borrowck::build_borrowck_dataflow_data_for_fn(tcx, fn_like.to_fn_parts(), &cfg); let lcfg = borrowck_dot::DataflowLabeller { inner: lcfg, @@ -760,13 +757,13 @@ pub fn fold_crate(krate: ast::Crate, ppm: PpMode) -> ast::Crate { fn get_source(input: &Input, sess: &Session) -> (Vec, String) { let src_name = driver::source_name(input); let src = sess.codemap() - .get_filemap(&src_name) - .unwrap() - .src - .as_ref() - .unwrap() - .as_bytes() - .to_vec(); + .get_filemap(&src_name) + .unwrap() + .src + .as_ref() + .unwrap() + .as_bytes() + .to_vec(); (src, src_name) } @@ -799,17 +796,18 @@ pub fn print_after_parsing(sess: &Session, // Silently ignores an identified node. let out: &mut Write = &mut out; s.call_with_pp_support(sess, None, box out, |annotation, out| { - debug!("pretty printing source code {:?}", s); - let sess = annotation.sess(); - pprust::print_crate(sess.codemap(), - sess.diagnostic(), - krate, - src_name.to_string(), - &mut rdr, - out, - annotation.pp_ann(), - false) - }).unwrap() + debug!("pretty printing source code {:?}", s); + let sess = annotation.sess(); + pprust::print_crate(sess.codemap(), + sess.diagnostic(), + krate, + src_name.to_string(), + &mut rdr, + out, + annotation.pp_ann(), + false) + }) + .unwrap() } else { unreachable!(); }; @@ -832,8 +830,15 @@ pub fn print_after_hir_lowering<'tcx, 'a: 'tcx>(sess: &'a Session, let _ignore = dep_graph.in_ignore(); if ppm.needs_analysis() { - print_with_analysis(sess, ast_map, analysis, resolutions, - crate_name, arenas, ppm, opt_uii, ofile); + print_with_analysis(sess, + ast_map, + analysis, + resolutions, + crate_name, + arenas, + ppm, + opt_uii, + ofile); return; } @@ -843,82 +848,82 @@ pub fn print_after_hir_lowering<'tcx, 'a: 'tcx>(sess: &'a Session, let mut out = Vec::new(); match (ppm, opt_uii) { - (PpmSource(s), _) => { - // Silently ignores an identified node. - let out: &mut Write = &mut out; - s.call_with_pp_support(sess, Some(ast_map), box out, |annotation, out| { - debug!("pretty printing source code {:?}", s); - let sess = annotation.sess(); - pprust::print_crate(sess.codemap(), - sess.diagnostic(), - krate, - src_name.to_string(), - &mut rdr, - out, - annotation.pp_ann(), - true) - }) - } + (PpmSource(s), _) => { + // Silently ignores an identified node. + let out: &mut Write = &mut out; + s.call_with_pp_support(sess, Some(ast_map), box out, |annotation, out| { + debug!("pretty printing source code {:?}", s); + let sess = annotation.sess(); + pprust::print_crate(sess.codemap(), + sess.diagnostic(), + krate, + src_name.to_string(), + &mut rdr, + out, + annotation.pp_ann(), + true) + }) + } - (PpmHir(s), None) => { - let out: &mut Write = &mut out; - s.call_with_pp_support_hir(sess, - ast_map, - analysis, - resolutions, - arenas, - crate_name, - box out, - |annotation, out, krate| { - debug!("pretty printing source code {:?}", s); - let sess = annotation.sess(); - pprust_hir::print_crate(sess.codemap(), - sess.diagnostic(), - krate, - src_name.to_string(), - &mut rdr, - out, - annotation.pp_ann(), - true) - }) - } + (PpmHir(s), None) => { + let out: &mut Write = &mut out; + s.call_with_pp_support_hir(sess, + ast_map, + analysis, + resolutions, + arenas, + crate_name, + box out, + |annotation, out, krate| { + debug!("pretty printing source code {:?}", s); + let sess = annotation.sess(); + pprust_hir::print_crate(sess.codemap(), + sess.diagnostic(), + krate, + src_name.to_string(), + &mut rdr, + out, + annotation.pp_ann(), + true) + }) + } - (PpmHir(s), Some(uii)) => { - let out: &mut Write = &mut out; - s.call_with_pp_support_hir(sess, - ast_map, - analysis, - resolutions, - arenas, - crate_name, - (out,uii), - |annotation, (out,uii), _| { - debug!("pretty printing source code {:?}", s); - let sess = annotation.sess(); - let ast_map = annotation.ast_map().expect("--unpretty missing HIR map"); - let mut pp_state = - pprust_hir::State::new_from_input(sess.codemap(), - sess.diagnostic(), - src_name.to_string(), - &mut rdr, - box out, - annotation.pp_ann(), - true, - Some(ast_map.krate())); - for node_id in uii.all_matching_node_ids(ast_map) { - let node = ast_map.get(node_id); - pp_state.print_node(&node)?; - pp::space(&mut pp_state.s)?; - let path = annotation.node_path(node_id) - .expect("--unpretty missing node paths"); - pp_state.synth_comment(path)?; - pp::hardbreak(&mut pp_state.s)?; - } - pp::eof(&mut pp_state.s) - }) - } - _ => unreachable!(), - }.unwrap(); + (PpmHir(s), Some(uii)) => { + let out: &mut Write = &mut out; + s.call_with_pp_support_hir(sess, + ast_map, + analysis, + resolutions, + arenas, + crate_name, + (out, uii), + |annotation, (out, uii), _| { + debug!("pretty printing source code {:?}", s); + let sess = annotation.sess(); + let ast_map = annotation.ast_map().expect("--unpretty missing HIR map"); + let mut pp_state = pprust_hir::State::new_from_input(sess.codemap(), + sess.diagnostic(), + src_name.to_string(), + &mut rdr, + box out, + annotation.pp_ann(), + true, + Some(ast_map.krate())); + for node_id in uii.all_matching_node_ids(ast_map) { + let node = ast_map.get(node_id); + pp_state.print_node(&node)?; + pp::space(&mut pp_state.s)?; + let path = annotation.node_path(node_id) + .expect("--unpretty missing node paths"); + pp_state.synth_comment(path)?; + pp::hardbreak(&mut pp_state.s)?; + } + pp::eof(&mut pp_state.s) + }) + } + _ => unreachable!(), + } + .unwrap(); write_output(out, ofile); } @@ -952,38 +957,35 @@ fn print_with_analysis<'tcx, 'a: 'tcx>(sess: &'a Session, resolutions.clone(), arenas, crate_name, - |tcx, mir_map, _, _, _| { + |tcx, _, _, _| { match ppm { PpmMir | PpmMirCFG => { - if let Some(mir_map) = mir_map { - if let Some(nodeid) = nodeid { - let def_id = tcx.map.local_def_id(nodeid); - match ppm { - PpmMir => write_mir_pretty(tcx, iter::once(def_id), &mir_map, &mut out), - PpmMirCFG => { - write_mir_graphviz(tcx, iter::once(def_id), &mir_map, &mut out) - } - _ => unreachable!(), - }?; - } else { - match ppm { - PpmMir => write_mir_pretty(tcx, - mir_map.map.keys().into_iter(), - &mir_map, - &mut out), - PpmMirCFG => write_mir_graphviz(tcx, - mir_map.map.keys().into_iter(), - &mir_map, - &mut out), - _ => unreachable!(), - }?; - } + if let Some(nodeid) = nodeid { + let def_id = tcx.map.local_def_id(nodeid); + match ppm { + PpmMir => write_mir_pretty(tcx, iter::once(def_id), &mut out), + PpmMirCFG => write_mir_graphviz(tcx, iter::once(def_id), &mut out), + _ => unreachable!(), + }?; + } else { + match ppm { + PpmMir => { + write_mir_pretty(tcx, tcx.mir_map.borrow().keys().into_iter(), &mut out) + } + PpmMirCFG => { + write_mir_graphviz(tcx, + tcx.mir_map.borrow().keys().into_iter(), + &mut out) + } + _ => unreachable!(), + }?; } Ok(()) } PpmFlowGraph(mode) => { - let nodeid = nodeid.expect("`pretty flowgraph=..` needs NodeId (int) or \ - unique path suffix (b::c::d)"); + let nodeid = + nodeid.expect("`pretty flowgraph=..` needs NodeId (int) or unique path \ + suffix (b::c::d)"); let node = tcx.map.find(nodeid).unwrap_or_else(|| { tcx.sess.fatal(&format!("--pretty flowgraph couldn't find id: {}", nodeid)) }); @@ -995,16 +997,11 @@ fn print_with_analysis<'tcx, 'a: 'tcx>(sess: &'a Session, let out: &mut Write = &mut out; - print_flowgraph(variants, - tcx, - mir_map.as_ref(), - code, - mode, - out) + print_flowgraph(variants, tcx, code, mode, out) } None => { - let message = format!("--pretty=flowgraph needs block, fn, or method; got \ - {:?}", + let message = format!("--pretty=flowgraph needs block, fn, or method; \ + got {:?}", node); // Point to what was found, if there's an accessible span. @@ -1017,7 +1014,9 @@ fn print_with_analysis<'tcx, 'a: 'tcx>(sess: &'a Session, } _ => unreachable!(), } - }), sess).unwrap(); + }), + sess) + .unwrap(); write_output(out, ofile); } diff --git a/src/librustc_driver/target_features.rs b/src/librustc_driver/target_features.rs index f202030308..ba51947a33 100644 --- a/src/librustc_driver/target_features.rs +++ b/src/librustc_driver/target_features.rs @@ -20,26 +20,11 @@ use libc::c_char; // detection code will walk past the end of the feature array, // leading to crashes. -const ARM_WHITELIST: &'static [&'static str] = &[ - "neon\0", - "vfp2\0", - "vfp3\0", - "vfp4\0", -]; +const ARM_WHITELIST: &'static [&'static str] = &["neon\0", "vfp2\0", "vfp3\0", "vfp4\0"]; -const X86_WHITELIST: &'static [&'static str] = &[ - "avx\0", - "avx2\0", - "bmi\0", - "bmi2\0", - "sse\0", - "sse2\0", - "sse3\0", - "sse4.1\0", - "sse4.2\0", - "ssse3\0", - "tbm\0", -]; +const X86_WHITELIST: &'static [&'static str] = &["avx\0", "avx2\0", "bmi\0", "bmi2\0", "sse\0", + "sse2\0", "sse3\0", "sse4.1\0", "sse4.2\0", + "ssse3\0", "tbm\0"]; /// Add `target_feature = "..."` cfgs for a variety of platform /// specific features (SSE, NEON etc.). @@ -59,7 +44,7 @@ pub fn add_configuration(cfg: &mut ast::CrateConfig, sess: &Session) { for feat in whitelist { assert_eq!(feat.chars().last(), Some('\0')); if unsafe { LLVMRustHasFeature(target_machine, feat.as_ptr() as *const c_char) } { - cfg.push(attr::mk_name_value_item_str(tf.clone(), intern(&feat[..feat.len()-1]))) + cfg.push(attr::mk_name_value_item_str(tf.clone(), intern(&feat[..feat.len() - 1]))) } } } diff --git a/src/librustc_driver/test.rs b/src/librustc_driver/test.rs index f6772b8771..8dc2155014 100644 --- a/src/librustc_driver/test.rs +++ b/src/librustc_driver/test.rs @@ -20,14 +20,13 @@ use rustc::middle::region::{self, CodeExtent}; use rustc::middle::region::CodeExtentData; use rustc::middle::resolve_lifetime; use rustc::middle::stability; -use rustc::ty::subst::{Kind, Subst, Substs}; +use rustc::ty::subst::{Kind, Subst}; use rustc::traits::Reveal; use rustc::ty::{self, Ty, TyCtxt, TypeFoldable}; use rustc::infer::{self, InferOk, InferResult, TypeOrigin}; use rustc_metadata::cstore::CStore; use rustc::hir::map as hir_map; use rustc::session::{self, config}; -use std::iter; use std::rc::Rc; use syntax::ast; use syntax::abi::Abi; @@ -41,7 +40,7 @@ use syntax_pos::DUMMY_SP; use rustc::hir; -struct Env<'a, 'gcx: 'a+'tcx, 'tcx: 'a> { +struct Env<'a, 'gcx: 'a + 'tcx, 'tcx: 'a> { infcx: &'a infer::InferCtxt<'a, 'gcx, 'tcx>, } @@ -87,8 +86,7 @@ impl Emitter for ExpectErrorEmitter { fn errors(msgs: &[&str]) -> (Box, usize) { let v = msgs.iter().map(|m| m.to_string()).collect(); - (box ExpectErrorEmitter { messages: v } as Box, - msgs.len()) + (box ExpectErrorEmitter { messages: v } as Box, msgs.len()) } fn test_env(source_string: &str, @@ -104,19 +102,28 @@ fn test_env(source_string: &str, let dep_graph = DepGraph::new(false); let _ignore = dep_graph.in_ignore(); let cstore = Rc::new(CStore::new(&dep_graph)); - let sess = session::build_session_(options, &dep_graph, None, diagnostic_handler, - Rc::new(CodeMap::new()), cstore.clone()); + let sess = session::build_session_(options, + &dep_graph, + None, + diagnostic_handler, + Rc::new(CodeMap::new()), + cstore.clone()); rustc_lint::register_builtins(&mut sess.lint_store.borrow_mut(), Some(&sess)); - let krate_config = Vec::new(); let input = config::Input::Str { name: driver::anon_src(), input: source_string.to_string(), }; - let krate = driver::phase_1_parse_input(&sess, krate_config, &input).unwrap(); + let krate = driver::phase_1_parse_input(&sess, &input).unwrap(); let driver::ExpansionResult { defs, resolutions, mut hir_forest, .. } = { - driver::phase_2_configure_and_expand( - &sess, &cstore, krate, None, "test", None, MakeGlobMap::No, |_| Ok(()), - ).expect("phase 2 aborted") + driver::phase_2_configure_and_expand(&sess, + &cstore, + krate, + None, + "test", + None, + MakeGlobMap::No, + |_| Ok(())) + .expect("phase 2 aborted") }; let _ignore = dep_graph.in_ignore(); @@ -169,14 +176,22 @@ impl<'a, 'gcx, 'tcx> Env<'a, 'gcx, 'tcx> { let node = ast::NodeId::from_u32; let dscope = self.infcx - .tcx - .region_maps - .intern_code_extent(CodeExtentData::DestructionScope(node(1)), - region::ROOT_CODE_EXTENT); + .tcx + .region_maps + .intern_code_extent(CodeExtentData::DestructionScope(node(1)), + region::ROOT_CODE_EXTENT); self.create_region_hierarchy(&RH { - id: node(1), - sub: &[RH { id: node(10), sub: &[] }, RH { id: node(11), sub: &[] }], - }, dscope); + id: node(1), + sub: &[RH { + id: node(10), + sub: &[], + }, + RH { + id: node(11), + sub: &[], + }], + }, + dscope); } #[allow(dead_code)] // this seems like it could be useful, even if we don't use it now @@ -215,22 +230,16 @@ impl<'a, 'gcx, 'tcx> Env<'a, 'gcx, 'tcx> { hir::ItemStatic(..) | hir::ItemFn(..) | hir::ItemForeignMod(..) | - hir::ItemTy(..) => { - None - } + hir::ItemTy(..) => None, hir::ItemEnum(..) | hir::ItemStruct(..) | hir::ItemUnion(..) | hir::ItemTrait(..) | hir::ItemImpl(..) | - hir::ItemDefaultImpl(..) => { - None - } + hir::ItemDefaultImpl(..) => None, - hir::ItemMod(ref m) => { - search_mod(this, m, idx, names) - } + hir::ItemMod(ref m) => search_mod(this, m, idx, names), }; } } @@ -275,7 +284,7 @@ impl<'a, 'gcx, 'tcx> Env<'a, 'gcx, 'tcx> { } pub fn t_pair(&self, ty1: Ty<'tcx>, ty2: Ty<'tcx>) -> Ty<'tcx> { - self.infcx.tcx.mk_tup(vec![ty1, ty2]) + self.infcx.tcx.intern_tup(&[ty1, ty2]) } pub fn t_param(&self, index: u32) -> Ty<'tcx> { @@ -283,10 +292,7 @@ impl<'a, 'gcx, 'tcx> Env<'a, 'gcx, 'tcx> { self.infcx.tcx.mk_param(index, token::intern(&name[..])) } - pub fn re_early_bound(&self, - index: u32, - name: &'static str) - -> &'tcx ty::Region { + pub fn re_early_bound(&self, index: u32, name: &'static str) -> &'tcx ty::Region { let name = token::intern(name); self.infcx.tcx.mk_region(ty::ReEarlyBound(ty::EarlyBoundRegion { index: index, @@ -294,7 +300,9 @@ impl<'a, 'gcx, 'tcx> Env<'a, 'gcx, 'tcx> { })) } - pub fn re_late_bound_with_debruijn(&self, id: u32, debruijn: ty::DebruijnIndex) + pub fn re_late_bound_with_debruijn(&self, + id: u32, + debruijn: ty::DebruijnIndex) -> &'tcx ty::Region { self.infcx.tcx.mk_region(ty::ReLateBound(debruijn, ty::BrAnon(id))) } @@ -396,9 +404,7 @@ impl<'a, 'gcx, 'tcx> Env<'a, 'gcx, 'tcx> { self.assert_eq(t, t_lub); } - Err(ref e) => { - panic!("unexpected error in LUB: {}", e) - } + Err(ref e) => panic!("unexpected error in LUB: {}", e), } } @@ -406,9 +412,7 @@ impl<'a, 'gcx, 'tcx> Env<'a, 'gcx, 'tcx> { pub fn check_glb(&self, t1: Ty<'tcx>, t2: Ty<'tcx>, t_glb: Ty<'tcx>) { debug!("check_glb(t1={}, t2={}, t_glb={})", t1, t2, t_glb); match self.glb(t1, t2) { - Err(e) => { - panic!("unexpected error computing LUB: {:?}", e) - } + Err(e) => panic!("unexpected error computing LUB: {:?}", e), Ok(InferOk { obligations, value: t }) => { // FIXME(#32730) once obligations are being propagated, assert the right thing. assert!(obligations.is_empty()); @@ -679,7 +683,7 @@ fn subst_ty_renumber_bound() { env.t_fn(&[t_param], env.t_nil()) }; - let substs = Substs::new(env.infcx.tcx, iter::once(Kind::from(t_rptr_bound1))); + let substs = env.infcx.tcx.intern_substs(&[Kind::from(t_rptr_bound1)]); let t_substituted = t_source.subst(env.infcx.tcx, substs); // t_expected = fn(&'a isize) @@ -714,7 +718,7 @@ fn subst_ty_renumber_some_bounds() { env.t_pair(t_param, env.t_fn(&[t_param], env.t_nil())) }; - let substs = Substs::new(env.infcx.tcx, iter::once(Kind::from(t_rptr_bound1))); + let substs = env.infcx.tcx.intern_substs(&[Kind::from(t_rptr_bound1)]); let t_substituted = t_source.subst(env.infcx.tcx, substs); // t_expected = (&'a isize, fn(&'a isize)) @@ -776,7 +780,7 @@ fn subst_region_renumber_region() { env.t_fn(&[env.t_rptr(re_early)], env.t_nil()) }; - let substs = Substs::new(env.infcx.tcx, iter::once(Kind::from(re_bound1))); + let substs = env.infcx.tcx.intern_substs(&[Kind::from(re_bound1)]); let t_substituted = t_source.subst(env.infcx.tcx, substs); // t_expected = fn(&'a isize) @@ -803,8 +807,8 @@ fn walk_ty() { let tcx = env.infcx.tcx; let int_ty = tcx.types.isize; let uint_ty = tcx.types.usize; - let tup1_ty = tcx.mk_tup(vec![int_ty, uint_ty, int_ty, uint_ty]); - let tup2_ty = tcx.mk_tup(vec![tup1_ty, tup1_ty, uint_ty]); + let tup1_ty = tcx.intern_tup(&[int_ty, uint_ty, int_ty, uint_ty]); + let tup2_ty = tcx.intern_tup(&[tup1_ty, tup1_ty, uint_ty]); let uniq_ty = tcx.mk_box(tup2_ty); let walked: Vec<_> = uniq_ty.walk().collect(); assert_eq!(walked, @@ -819,8 +823,8 @@ fn walk_ty_skip_subtree() { let tcx = env.infcx.tcx; let int_ty = tcx.types.isize; let uint_ty = tcx.types.usize; - let tup1_ty = tcx.mk_tup(vec![int_ty, uint_ty, int_ty, uint_ty]); - let tup2_ty = tcx.mk_tup(vec![tup1_ty, tup1_ty, uint_ty]); + let tup1_ty = tcx.intern_tup(&[int_ty, uint_ty, int_ty, uint_ty]); + let tup2_ty = tcx.intern_tup(&[tup1_ty, tup1_ty, uint_ty]); let uniq_ty = tcx.mk_box(tup2_ty); // types we expect to see (in order), plus a boolean saying diff --git a/src/librustc_errors/Cargo.toml b/src/librustc_errors/Cargo.toml index 128c270eb3..c92e4d8f5a 100644 --- a/src/librustc_errors/Cargo.toml +++ b/src/librustc_errors/Cargo.toml @@ -11,4 +11,4 @@ crate-type = ["dylib"] [dependencies] log = { path = "../liblog" } serialize = { path = "../libserialize" } -syntax_pos = { path = "../libsyntax_pos" } \ No newline at end of file +syntax_pos = { path = "../libsyntax_pos" } diff --git a/src/librustc_errors/diagnostic.rs b/src/librustc_errors/diagnostic.rs new file mode 100644 index 0000000000..730ca8f9e2 --- /dev/null +++ b/src/librustc_errors/diagnostic.rs @@ -0,0 +1,202 @@ +// 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. + +use CodeSuggestion; +use Level; +use RenderSpan; +use RenderSpan::Suggestion; +use std::fmt; +use syntax_pos::{MultiSpan, Span}; + +#[must_use] +#[derive(Clone, Debug, PartialEq)] +pub struct Diagnostic { + pub level: Level, + pub message: String, + pub code: Option, + pub span: MultiSpan, + pub children: Vec, +} + +/// For example a note attached to an error. +#[derive(Clone, Debug, PartialEq)] +pub struct SubDiagnostic { + pub level: Level, + pub message: String, + pub span: MultiSpan, + pub render_span: Option, +} + +impl Diagnostic { + pub fn new(level: Level, message: &str) -> Self { + Diagnostic::new_with_code(level, None, message) + } + + pub fn new_with_code(level: Level, code: Option, message: &str) -> Self { + Diagnostic { + level: level, + message: message.to_owned(), + code: code, + span: MultiSpan::new(), + children: vec![], + } + } + + /// Cancel the diagnostic (a structured diagnostic must either be emitted or + /// cancelled or it will panic when dropped). + /// BEWARE: if this DiagnosticBuilder is an error, then creating it will + /// bump the error count on the Handler and cancelling it won't undo that. + /// If you want to decrement the error count you should use `Handler::cancel`. + pub fn cancel(&mut self) { + self.level = Level::Cancelled; + } + + pub fn cancelled(&self) -> bool { + self.level == Level::Cancelled + } + + pub fn is_fatal(&self) -> bool { + self.level == Level::Fatal + } + + /// Add a span/label to be included in the resulting snippet. + /// This is pushed onto the `MultiSpan` that was created when the + /// diagnostic was first built. If you don't call this function at + /// all, and you just supplied a `Span` to create the diagnostic, + /// then the snippet will just include that `Span`, which is + /// called the primary span. + pub fn span_label(&mut self, span: Span, label: &fmt::Display) + -> &mut Self { + self.span.push_span_label(span, format!("{}", label)); + self + } + + pub fn note_expected_found(&mut self, + label: &fmt::Display, + expected: &fmt::Display, + found: &fmt::Display) + -> &mut Self + { + self.note_expected_found_extra(label, expected, found, &"", &"") + } + + pub fn note_expected_found_extra(&mut self, + label: &fmt::Display, + expected: &fmt::Display, + found: &fmt::Display, + expected_extra: &fmt::Display, + found_extra: &fmt::Display) + -> &mut Self + { + // For now, just attach these as notes + self.note(&format!("expected {} `{}`{}", label, expected, expected_extra)); + self.note(&format!(" found {} `{}`{}", label, found, found_extra)); + self + } + + pub fn note(&mut self, msg: &str) -> &mut Self { + self.sub(Level::Note, msg, MultiSpan::new(), None); + self + } + + pub fn span_note>(&mut self, + sp: S, + msg: &str) + -> &mut Self { + self.sub(Level::Note, msg, sp.into(), None); + self + } + + pub fn warn(&mut self, msg: &str) -> &mut Self { + self.sub(Level::Warning, msg, MultiSpan::new(), None); + self + } + + pub fn span_warn>(&mut self, + sp: S, + msg: &str) + -> &mut Self { + self.sub(Level::Warning, msg, sp.into(), None); + self + } + + pub fn help(&mut self , msg: &str) -> &mut Self { + self.sub(Level::Help, msg, MultiSpan::new(), None); + self + } + + pub fn span_help>(&mut self, + sp: S, + msg: &str) + -> &mut Self { + self.sub(Level::Help, msg, sp.into(), None); + self + } + + /// Prints out a message with a suggested edit of the code. + /// + /// See `diagnostic::RenderSpan::Suggestion` for more information. + pub fn span_suggestion>(&mut self, + sp: S, + msg: &str, + suggestion: String) + -> &mut Self { + self.sub(Level::Help, + msg, + MultiSpan::new(), + Some(Suggestion(CodeSuggestion { + msp: sp.into(), + substitutes: vec![suggestion], + }))); + self + } + + pub fn set_span>(&mut self, sp: S) -> &mut Self { + self.span = sp.into(); + self + } + + pub fn code(&mut self, s: String) -> &mut Self { + self.code = Some(s); + self + } + + pub fn message(&self) -> &str { + &self.message + } + + pub fn level(&self) -> Level { + self.level + } + + /// Used by a lint. Copies over all details *but* the "main + /// message". + pub fn copy_details_not_message(&mut self, from: &Diagnostic) { + self.span = from.span.clone(); + self.code = from.code.clone(); + self.children.extend(from.children.iter().cloned()) + } + + /// Convenience function for internal use, clients should use one of the + /// public methods above. + fn sub(&mut self, + level: Level, + message: &str, + span: MultiSpan, + render_span: Option) { + let sub = SubDiagnostic { + level: level, + message: message.to_owned(), + span: span, + render_span: render_span, + }; + self.children.push(sub); + } +} diff --git a/src/librustc_errors/diagnostic_builder.rs b/src/librustc_errors/diagnostic_builder.rs new file mode 100644 index 0000000000..7dfea6b895 --- /dev/null +++ b/src/librustc_errors/diagnostic_builder.rs @@ -0,0 +1,196 @@ +// 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. + +use Diagnostic; +use Level; +use Handler; +use std::fmt::{self, Debug}; +use std::ops::{Deref, DerefMut}; +use std::thread::panicking; +use syntax_pos::{MultiSpan, Span}; + +/// Used for emitting structured error messages and other diagnostic information. +#[must_use] +#[derive(Clone)] +pub struct DiagnosticBuilder<'a> { + handler: &'a Handler, + diagnostic: Diagnostic, +} + +/// In general, the `DiagnosticBuilder` uses deref to allow access to +/// the fields and methods of the embedded `diagnostic` in a +/// transparent way. *However,* many of the methods are intended to +/// be used in a chained way, and hence ought to return `self`. In +/// that case, we can't just naively forward to the method on the +/// `diagnostic`, because the return type would be a `&Diagnostic` +/// instead of a `&DiagnosticBuilder<'a>`. This `forward!` macro makes +/// it easy to declare such methods on the builder. +macro_rules! forward { + // Forward pattern for &self -> &Self + (pub fn $n:ident(&self, $($name:ident: $ty:ty),*) -> &Self) => { + pub fn $n(&self, $($name: $ty),*) -> &Self { + self.diagnostic.$n($($name),*); + self + } + }; + + // Forward pattern for &mut self -> &mut Self + (pub fn $n:ident(&mut self, $($name:ident: $ty:ty),*) -> &mut Self) => { + pub fn $n(&mut self, $($name: $ty),*) -> &mut Self { + self.diagnostic.$n($($name),*); + self + } + }; + + // Forward pattern for &mut self -> &mut Self, with S: Into + // type parameter. No obvious way to make this more generic. + (pub fn $n:ident>(&mut self, $($name:ident: $ty:ty),*) -> &mut Self) => { + pub fn $n>(&mut self, $($name: $ty),*) -> &mut Self { + self.diagnostic.$n($($name),*); + self + } + }; +} + +impl<'a> Deref for DiagnosticBuilder<'a> { + type Target = Diagnostic; + + fn deref(&self) -> &Diagnostic { + &self.diagnostic + } +} + +impl<'a> DerefMut for DiagnosticBuilder<'a> { + fn deref_mut(&mut self) -> &mut Diagnostic { + &mut self.diagnostic + } +} + +impl<'a> DiagnosticBuilder<'a> { + /// Emit the diagnostic. + pub fn emit(&mut self) { + if self.cancelled() { + return; + } + + match self.level { + Level::Bug | + Level::Fatal | + Level::PhaseFatal | + Level::Error => { + self.handler.bump_err_count(); + } + + Level::Warning | + Level::Note | + Level::Help | + Level::Cancelled => { + } + } + + self.handler.emitter.borrow_mut().emit(&self); + self.cancel(); + self.handler.panic_if_treat_err_as_bug(); + + // if self.is_fatal() { + // panic!(FatalError); + // } + } + + /// Add a span/label to be included in the resulting snippet. + /// This is pushed onto the `MultiSpan` that was created when the + /// diagnostic was first built. If you don't call this function at + /// all, and you just supplied a `Span` to create the diagnostic, + /// then the snippet will just include that `Span`, which is + /// called the primary span. + forward!(pub fn span_label(&mut self, span: Span, label: &fmt::Display) + -> &mut Self); + + forward!(pub fn note_expected_found(&mut self, + label: &fmt::Display, + expected: &fmt::Display, + found: &fmt::Display) + -> &mut Self); + + forward!(pub fn note_expected_found_extra(&mut self, + label: &fmt::Display, + expected: &fmt::Display, + found: &fmt::Display, + expected_extra: &fmt::Display, + found_extra: &fmt::Display) + -> &mut Self); + + forward!(pub fn note(&mut self, msg: &str) -> &mut Self); + forward!(pub fn span_note>(&mut self, + sp: S, + msg: &str) + -> &mut Self); + forward!(pub fn warn(&mut self, msg: &str) -> &mut Self); + forward!(pub fn span_warn>(&mut self, sp: S, msg: &str) -> &mut Self); + forward!(pub fn help(&mut self , msg: &str) -> &mut Self); + forward!(pub fn span_help>(&mut self, + sp: S, + msg: &str) + -> &mut Self); + forward!(pub fn span_suggestion>(&mut self, + sp: S, + msg: &str, + suggestion: String) + -> &mut Self); + forward!(pub fn set_span>(&mut self, sp: S) -> &mut Self); + forward!(pub fn code(&mut self, s: String) -> &mut Self); + + /// Convenience function for internal use, clients should use one of the + /// struct_* methods on Handler. + pub fn new(handler: &'a Handler, level: Level, message: &str) -> DiagnosticBuilder<'a> { + DiagnosticBuilder::new_with_code(handler, level, None, message) + } + + /// Convenience function for internal use, clients should use one of the + /// struct_* methods on Handler. + pub fn new_with_code(handler: &'a Handler, + level: Level, + code: Option, + message: &str) + -> DiagnosticBuilder<'a> { + DiagnosticBuilder { + handler: handler, + diagnostic: Diagnostic::new_with_code(level, code, message) + } + } + + pub fn into_diagnostic(mut self) -> Diagnostic { + // annoyingly, the Drop impl means we can't actually move + let result = self.diagnostic.clone(); + self.cancel(); + result + } +} + +impl<'a> Debug for DiagnosticBuilder<'a> { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + self.diagnostic.fmt(f) + } +} + +/// Destructor bomb - a DiagnosticBuilder must be either emitted or cancelled or +/// we emit a bug. +impl<'a> Drop for DiagnosticBuilder<'a> { + fn drop(&mut self) { + if !panicking() && !self.cancelled() { + let mut db = DiagnosticBuilder::new(self.handler, + Level::Bug, + "Error constructed but not emitted"); + db.emit(); + panic!(); + } + } +} + diff --git a/src/librustc_errors/emitter.rs b/src/librustc_errors/emitter.rs index 6456b72dfb..a307e9b696 100644 --- a/src/librustc_errors/emitter.rs +++ b/src/librustc_errors/emitter.rs @@ -51,8 +51,8 @@ impl ColorConfig { fn use_color(&self) -> bool { match *self { ColorConfig::Always => true, - ColorConfig::Never => false, - ColorConfig::Auto => stderr_isatty(), + ColorConfig::Never => false, + ColorConfig::Auto => stderr_isatty(), } } } @@ -83,31 +83,33 @@ macro_rules! println_maybe_styled { } impl EmitterWriter { - pub fn stderr(color_config: ColorConfig, - code_map: Option>) - -> EmitterWriter { + pub fn stderr(color_config: ColorConfig, code_map: Option>) -> EmitterWriter { if color_config.use_color() { let dst = Destination::from_stderr(); - EmitterWriter { dst: dst, - cm: code_map} + EmitterWriter { + dst: dst, + cm: code_map, + } } else { - EmitterWriter { dst: Raw(Box::new(io::stderr())), - cm: code_map} + EmitterWriter { + dst: Raw(Box::new(io::stderr())), + cm: code_map, + } } } - pub fn new(dst: Box, - code_map: Option>) - -> EmitterWriter { - EmitterWriter { dst: Raw(dst), - cm: code_map} + pub fn new(dst: Box, code_map: Option>) -> EmitterWriter { + EmitterWriter { + dst: Raw(dst), + cm: code_map, + } } fn preprocess_annotations(&self, msp: &MultiSpan) -> Vec { fn add_annotation_to_file(file_vec: &mut Vec, - file: Rc, - line_index: usize, - ann: Annotation) { + file: Rc, + line_index: usize, + ann: Annotation) { for slot in file_vec.iter_mut() { // Look through each of our files for the one we're adding to @@ -166,15 +168,15 @@ impl EmitterWriter { } add_annotation_to_file(&mut output, - lo.file, - lo.line, - Annotation { - start_col: lo.col.0, - end_col: hi.col.0, - is_primary: span_label.is_primary, - is_minimized: is_minimized, - label: span_label.label.clone(), - }); + lo.file, + lo.line, + Annotation { + start_col: lo.col.0, + end_col: hi.col.0, + is_primary: span_label.is_primary, + is_minimized: is_minimized, + label: span_label.label.clone(), + }); } } output @@ -235,9 +237,7 @@ impl EmitterWriter { '^', Style::UnderlinePrimary); if !annotation.is_minimized { - buffer.set_style(line_offset, - width_offset + p, - Style::UnderlinePrimary); + buffer.set_style(line_offset, width_offset + p, Style::UnderlinePrimary); } } else { buffer.putc(line_offset + 1, @@ -245,9 +245,7 @@ impl EmitterWriter { '-', Style::UnderlineSecondary); if !annotation.is_minimized { - buffer.set_style(line_offset, - width_offset + p, - Style::UnderlineSecondary); + buffer.set_style(line_offset, width_offset + p, Style::UnderlineSecondary); } } } @@ -427,8 +425,7 @@ impl EmitterWriter { } // Check to make sure we're not in any <*macros> if !cm.span_to_filename(def_site).contains("macros>") && - !trace.macro_decl_name.starts_with("#[") - { + !trace.macro_decl_name.starts_with("#[") { new_labels.push((trace.call_site, "in this macro invocation".to_string())); break; @@ -473,10 +470,10 @@ impl EmitterWriter { if spans_updated { children.push(SubDiagnostic { level: Level::Note, - message:"this error originates in a macro outside of the current \ - crate".to_string(), + message: "this error originates in a macro outside of the current crate" + .to_string(), span: MultiSpan::new(), - render_span: None + render_span: None, }); } } @@ -500,8 +497,7 @@ impl EmitterWriter { buffer.append(0, &level.to_string(), Style::HeaderMsg); buffer.append(0, ": ", Style::NoStyle); buffer.append(0, msg, Style::NoStyle); - } - else { + } else { buffer.append(0, &level.to_string(), Style::Level(level.clone())); match code { &Some(ref code) => { @@ -520,23 +516,21 @@ impl EmitterWriter { let mut annotated_files = self.preprocess_annotations(msp); // Make sure our primary file comes first - let primary_lo = - if let (Some(ref cm), Some(ref primary_span)) = (self.cm.as_ref(), - msp.primary_span().as_ref()) { - if primary_span != &&DUMMY_SP && primary_span != &&COMMAND_LINE_SP { - cm.lookup_char_pos(primary_span.lo) - } - else { - emit_to_destination(&buffer.render(), level, &mut self.dst)?; - return Ok(()); - } + let primary_lo = if let (Some(ref cm), Some(ref primary_span)) = + (self.cm.as_ref(), msp.primary_span().as_ref()) { + if primary_span != &&DUMMY_SP && primary_span != &&COMMAND_LINE_SP { + cm.lookup_char_pos(primary_span.lo) } else { - // If we don't have span information, emit and exit emit_to_destination(&buffer.render(), level, &mut self.dst)?; return Ok(()); - }; + } + } else { + // If we don't have span information, emit and exit + emit_to_destination(&buffer.render(), level, &mut self.dst)?; + return Ok(()); + }; if let Ok(pos) = - annotated_files.binary_search_by(|x| x.file.name.cmp(&primary_lo.file.name)) { + annotated_files.binary_search_by(|x| x.file.name.cmp(&primary_lo.file.name)) { annotated_files.swap(0, pos); } @@ -552,8 +546,8 @@ impl EmitterWriter { buffer.prepend(buffer_msg_line_offset, "--> ", Style::LineNumber); let loc = primary_lo.clone(); buffer.append(buffer_msg_line_offset, - &format!("{}:{}:{}", loc.file.name, loc.line, loc.col.0 + 1), - Style::LineAndColumn); + &format!("{}:{}:{}", loc.file.name, loc.line, loc.col.0 + 1), + Style::LineAndColumn); for _ in 0..max_line_num_len { buffer.prepend(buffer_msg_line_offset, " ", Style::NoStyle); } @@ -567,8 +561,8 @@ impl EmitterWriter { // Then, the secondary file indicator buffer.prepend(buffer_msg_line_offset + 1, "::: ", Style::LineNumber); buffer.append(buffer_msg_line_offset + 1, - &annotated_file.file.name, - Style::LineAndColumn); + &annotated_file.file.name, + Style::LineAndColumn); for _ in 0..max_line_num_len { buffer.prepend(buffer_msg_line_offset + 1, " ", Style::NoStyle); } @@ -589,7 +583,7 @@ impl EmitterWriter { // this annotated line and the next one if line_idx < (annotated_file.lines.len() - 1) { let line_idx_delta = annotated_file.lines[line_idx + 1].line_index - - annotated_file.lines[line_idx].line_index; + annotated_file.lines[line_idx].line_index; if line_idx_delta > 2 { let last_buffer_line_num = buffer.num_lines(); buffer.puts(last_buffer_line_num, 0, "...", Style::LineNumber); @@ -670,12 +664,7 @@ impl EmitterWriter { let max_line_num = self.get_max_line_num(span, children); let max_line_num_len = max_line_num.to_string().len(); - match self.emit_message_default(span, - message, - code, - level, - max_line_num_len, - false) { + match self.emit_message_default(span, message, code, level, max_line_num_len, false) { Ok(()) => { if !children.is_empty() { let mut buffer = StyledBuffer::new(); @@ -721,13 +710,15 @@ impl EmitterWriter { } } } - Err(e) => panic!("failed to emit error: {}", e) + Err(e) => panic!("failed to emit error: {}", e), } match write!(&mut self.dst, "\n") { Err(e) => panic!("failed to emit error: {}", e), - _ => match self.dst.flush() { - Err(e) => panic!("failed to emit error: {}", e), - _ => () + _ => { + match self.dst.flush() { + Err(e) => panic!("failed to emit error: {}", e), + _ => (), + } } } } @@ -751,8 +742,9 @@ fn overlaps(a1: &Annotation, a2: &Annotation) -> bool { } fn emit_to_destination(rendered_buffer: &Vec>, - lvl: &Level, - dst: &mut Destination) -> io::Result<()> { + lvl: &Level, + dst: &mut Destination) + -> io::Result<()> { use lock; // In order to prevent error message interleaving, where multiple error lines get intermixed @@ -793,8 +785,7 @@ fn stderr_isatty() -> bool { const STD_ERROR_HANDLE: DWORD = -12i32 as DWORD; extern "system" { fn GetStdHandle(which: DWORD) -> HANDLE; - fn GetConsoleMode(hConsoleHandle: HANDLE, - lpMode: *mut DWORD) -> BOOL; + fn GetConsoleMode(hConsoleHandle: HANDLE, lpMode: *mut DWORD) -> BOOL; } unsafe { let handle = GetStdHandle(STD_ERROR_HANDLE); @@ -822,9 +813,7 @@ impl BufferedWriter { // note: we use _new because the conditional compilation at its use site may make this // this function unused on some platforms fn _new() -> BufferedWriter { - BufferedWriter { - buffer: vec![] - } + BufferedWriter { buffer: vec![] } } } @@ -851,35 +840,34 @@ impl Destination { /// When not on Windows, prefer the buffered terminal so that we can buffer an entire error /// to be emitted at one time. fn from_stderr() -> Destination { - let stderr: Option> = + let stderr: Option> = term::TerminfoTerminal::new(BufferedWriter::_new()) .map(|t| Box::new(t) as Box); match stderr { Some(t) => BufferedTerminal(t), - None => Raw(Box::new(io::stderr())), + None => Raw(Box::new(io::stderr())), } } #[cfg(windows)] /// Return a normal, unbuffered terminal when on Windows. fn from_stderr() -> Destination { - let stderr: Option> = - term::TerminfoTerminal::new(io::stderr()) - .map(|t| Box::new(t) as Box) - .or_else(|| term::WinConsole::new(io::stderr()).ok() - .map(|t| Box::new(t) as Box)); + let stderr: Option> = term::TerminfoTerminal::new(io::stderr()) + .map(|t| Box::new(t) as Box) + .or_else(|| { + term::WinConsole::new(io::stderr()) + .ok() + .map(|t| Box::new(t) as Box) + }); match stderr { Some(t) => Terminal(t), - None => Raw(Box::new(io::stderr())), + None => Raw(Box::new(io::stderr())), } } - fn apply_style(&mut self, - lvl: Level, - style: Style) - -> io::Result<()> { + fn apply_style(&mut self, lvl: Level, style: Style) -> io::Result<()> { match style { Style::FileNameStyle | Style::LineAndColumn => {} Style::LineNumber => { @@ -929,18 +917,26 @@ impl Destination { fn start_attr(&mut self, attr: term::Attr) -> io::Result<()> { match *self { - Terminal(ref mut t) => { t.attr(attr)?; } - BufferedTerminal(ref mut t) => { t.attr(attr)?; } - Raw(_) => { } + Terminal(ref mut t) => { + t.attr(attr)?; + } + BufferedTerminal(ref mut t) => { + t.attr(attr)?; + } + Raw(_) => {} } Ok(()) } fn reset_attrs(&mut self) -> io::Result<()> { match *self { - Terminal(ref mut t) => { t.reset()?; } - BufferedTerminal(ref mut t) => { t.reset()?; } - Raw(_) => { } + Terminal(ref mut t) => { + t.reset()?; + } + BufferedTerminal(ref mut t) => { + t.reset()?; + } + Raw(_) => {} } Ok(()) } diff --git a/src/librustc_errors/lib.rs b/src/librustc_errors/lib.rs index af8ac81b4f..badee66b83 100644 --- a/src/librustc_errors/lib.rs +++ b/src/librustc_errors/lib.rs @@ -28,8 +28,10 @@ extern crate serialize; extern crate term; -#[macro_use] extern crate log; -#[macro_use] extern crate libc; +#[macro_use] +extern crate log; +#[macro_use] +extern crate libc; extern crate rustc_unicode; extern crate serialize as rustc_serialize; // used by deriving extern crate syntax_pos; @@ -37,25 +39,25 @@ extern crate syntax_pos; pub use emitter::ColorConfig; use self::Level::*; -use self::RenderSpan::*; use emitter::{Emitter, EmitterWriter}; use std::cell::{RefCell, Cell}; use std::{error, fmt}; use std::rc::Rc; -use std::thread::panicking; +pub mod diagnostic; +pub mod diagnostic_builder; pub mod emitter; pub mod snippet; pub mod registry; pub mod styled_buffer; mod lock; -use syntax_pos::{BytePos, Loc, FileLinesResult, FileName, MultiSpan, Span, NO_EXPANSION }; -use syntax_pos::{MacroBacktrace}; +use syntax_pos::{BytePos, Loc, FileLinesResult, FileName, MultiSpan, Span, NO_EXPANSION}; +use syntax_pos::MacroBacktrace; -#[derive(Clone)] +#[derive(Clone, Debug, PartialEq)] pub enum RenderSpan { /// A FullSpan renders with both with an initial line for the /// message, prefixed by file:linenum, followed by a summary of @@ -69,7 +71,7 @@ pub enum RenderSpan { Suggestion(CodeSuggestion), } -#[derive(Clone)] +#[derive(Clone, Debug, PartialEq)] pub struct CodeSuggestion { pub msp: MultiSpan, pub substitutes: Vec, @@ -89,9 +91,11 @@ impl CodeSuggestion { pub fn splice_lines(&self, cm: &CodeMapper) -> String { use syntax_pos::{CharPos, Loc, Pos}; - fn push_trailing(buf: &mut String, line_opt: Option<&str>, - lo: &Loc, hi_opt: Option<&Loc>) { - let (lo, hi_opt) = (lo.col.to_usize(), hi_opt.map(|hi|hi.col.to_usize())); + fn push_trailing(buf: &mut String, + line_opt: Option<&str>, + lo: &Loc, + hi_opt: Option<&Loc>) { + let (lo, hi_opt) = (lo.col.to_usize(), hi_opt.map(|hi| hi.col.to_usize())); if let Some(line) = line_opt { if line.len() > lo { buf.push_str(match hi_opt { @@ -119,7 +123,11 @@ impl CodeSuggestion { // Find the bounding span. let lo = primary_spans.iter().map(|sp| sp.lo).min().unwrap(); let hi = primary_spans.iter().map(|sp| sp.hi).min().unwrap(); - let bounding_span = Span { lo: lo, hi: hi, expn_id: NO_EXPANSION }; + let bounding_span = Span { + lo: lo, + hi: hi, + expn_id: NO_EXPANSION, + }; let lines = cm.span_to_lines(bounding_span).unwrap(); assert!(!lines.lines.is_empty()); @@ -153,7 +161,7 @@ impl CodeSuggestion { } } if let Some(cur_line) = fm.get_line(cur_lo.line - 1) { - buf.push_str(&cur_line[.. cur_lo.col.to_usize()]); + buf.push_str(&cur_line[..cur_lo.col.to_usize()]); } } buf.push_str(substitute); @@ -203,221 +211,8 @@ impl error::Error for ExplicitBug { } } -/// Used for emitting structured error messages and other diagnostic information. -#[must_use] -#[derive(Clone)] -pub struct DiagnosticBuilder<'a> { - handler: &'a Handler, - pub level: Level, - pub message: String, - pub code: Option, - pub span: MultiSpan, - pub children: Vec, -} - -/// For example a note attached to an error. -#[derive(Clone)] -pub struct SubDiagnostic { - pub level: Level, - pub message: String, - pub span: MultiSpan, - pub render_span: Option, -} - -impl<'a> DiagnosticBuilder<'a> { - /// Emit the diagnostic. - pub fn emit(&mut self) { - if self.cancelled() { - return; - } - - self.handler.emitter.borrow_mut().emit(&self); - self.cancel(); - self.handler.panic_if_treat_err_as_bug(); - - // if self.is_fatal() { - // panic!(FatalError); - // } - } - - /// Cancel the diagnostic (a structured diagnostic must either be emitted or - /// cancelled or it will panic when dropped). - /// BEWARE: if this DiagnosticBuilder is an error, then creating it will - /// bump the error count on the Handler and cancelling it won't undo that. - /// If you want to decrement the error count you should use `Handler::cancel`. - pub fn cancel(&mut self) { - self.level = Level::Cancelled; - } - - pub fn cancelled(&self) -> bool { - self.level == Level::Cancelled - } - - pub fn is_fatal(&self) -> bool { - self.level == Level::Fatal - } - - /// Add a span/label to be included in the resulting snippet. - /// This is pushed onto the `MultiSpan` that was created when the - /// diagnostic was first built. If you don't call this function at - /// all, and you just supplied a `Span` to create the diagnostic, - /// then the snippet will just include that `Span`, which is - /// called the primary span. - pub fn span_label(&mut self, span: Span, label: &fmt::Display) - -> &mut DiagnosticBuilder<'a> { - self.span.push_span_label(span, format!("{}", label)); - self - } - - pub fn note_expected_found(&mut self, - label: &fmt::Display, - expected: &fmt::Display, - found: &fmt::Display) - -> &mut DiagnosticBuilder<'a> - { - self.note_expected_found_extra(label, expected, found, &"", &"") - } - - pub fn note_expected_found_extra(&mut self, - label: &fmt::Display, - expected: &fmt::Display, - found: &fmt::Display, - expected_extra: &fmt::Display, - found_extra: &fmt::Display) - -> &mut DiagnosticBuilder<'a> - { - // For now, just attach these as notes - self.note(&format!("expected {} `{}`{}", label, expected, expected_extra)); - self.note(&format!(" found {} `{}`{}", label, found, found_extra)); - self - } - - pub fn note(&mut self, msg: &str) -> &mut DiagnosticBuilder<'a> { - self.sub(Level::Note, msg, MultiSpan::new(), None); - self - } - pub fn span_note>(&mut self, - sp: S, - msg: &str) - -> &mut DiagnosticBuilder<'a> { - self.sub(Level::Note, msg, sp.into(), None); - self - } - pub fn warn(&mut self, msg: &str) -> &mut DiagnosticBuilder<'a> { - self.sub(Level::Warning, msg, MultiSpan::new(), None); - self - } - pub fn span_warn>(&mut self, - sp: S, - msg: &str) - -> &mut DiagnosticBuilder<'a> { - self.sub(Level::Warning, msg, sp.into(), None); - self - } - pub fn help(&mut self , msg: &str) -> &mut DiagnosticBuilder<'a> { - self.sub(Level::Help, msg, MultiSpan::new(), None); - self - } - pub fn span_help>(&mut self, - sp: S, - msg: &str) - -> &mut DiagnosticBuilder<'a> { - self.sub(Level::Help, msg, sp.into(), None); - self - } - /// Prints out a message with a suggested edit of the code. - /// - /// See `diagnostic::RenderSpan::Suggestion` for more information. - pub fn span_suggestion>(&mut self, - sp: S, - msg: &str, - suggestion: String) - -> &mut DiagnosticBuilder<'a> { - self.sub(Level::Help, msg, MultiSpan::new(), Some(Suggestion(CodeSuggestion { - msp: sp.into(), - substitutes: vec![suggestion], - }))); - self - } - - pub fn set_span>(&mut self, sp: S) -> &mut Self { - self.span = sp.into(); - self - } - - pub fn code(&mut self, s: String) -> &mut Self { - self.code = Some(s); - self - } - - pub fn message(&self) -> &str { - &self.message - } - - pub fn level(&self) -> Level { - self.level - } - - /// Convenience function for internal use, clients should use one of the - /// struct_* methods on Handler. - fn new(handler: &'a Handler, - level: Level, - message: &str) -> DiagnosticBuilder<'a> { - DiagnosticBuilder::new_with_code(handler, level, None, message) - } - - /// Convenience function for internal use, clients should use one of the - /// struct_* methods on Handler. - fn new_with_code(handler: &'a Handler, - level: Level, - code: Option, - message: &str) -> DiagnosticBuilder<'a> { - DiagnosticBuilder { - handler: handler, - level: level, - message: message.to_owned(), - code: code, - span: MultiSpan::new(), - children: vec![], - } - } - - /// Convenience function for internal use, clients should use one of the - /// public methods above. - fn sub(&mut self, - level: Level, - message: &str, - span: MultiSpan, - render_span: Option) { - let sub = SubDiagnostic { - level: level, - message: message.to_owned(), - span: span, - render_span: render_span, - }; - self.children.push(sub); - } -} - -impl<'a> fmt::Debug for DiagnosticBuilder<'a> { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - self.message.fmt(f) - } -} - -/// Destructor bomb - a DiagnosticBuilder must be either emitted or cancelled or -/// we emit a bug. -impl<'a> Drop for DiagnosticBuilder<'a> { - fn drop(&mut self) { - if !panicking() && !self.cancelled() { - let mut db = DiagnosticBuilder::new(self.handler, - Bug, - "Error constructed but not emitted"); - db.emit(); - panic!(); - } - } -} +pub use diagnostic::{Diagnostic, SubDiagnostic}; +pub use diagnostic_builder::DiagnosticBuilder; /// A handler deals with errors; certain errors /// (fatal, bug, unimpl) may cause immediate exit, @@ -443,7 +238,8 @@ impl Handler { pub fn with_emitter(can_emit_warnings: bool, treat_err_as_bug: bool, - e: Box) -> Handler { + e: Box) + -> Handler { Handler { err_count: Cell::new(0), emitter: RefCell::new(e), @@ -497,7 +293,6 @@ impl Handler { sp: S, msg: &str) -> DiagnosticBuilder<'a> { - self.bump_err_count(); let mut result = DiagnosticBuilder::new(self, Level::Error, msg); result.set_span(sp); result @@ -507,21 +302,18 @@ impl Handler { msg: &str, code: &str) -> DiagnosticBuilder<'a> { - self.bump_err_count(); let mut result = DiagnosticBuilder::new(self, Level::Error, msg); result.set_span(sp); result.code(code.to_owned()); result } pub fn struct_err<'a>(&'a self, msg: &str) -> DiagnosticBuilder<'a> { - self.bump_err_count(); DiagnosticBuilder::new(self, Level::Error, msg) } pub fn struct_span_fatal<'a, S: Into>(&'a self, sp: S, msg: &str) -> DiagnosticBuilder<'a> { - self.bump_err_count(); let mut result = DiagnosticBuilder::new(self, Level::Fatal, msg); result.set_span(sp); result @@ -531,24 +323,16 @@ impl Handler { msg: &str, code: &str) -> DiagnosticBuilder<'a> { - self.bump_err_count(); let mut result = DiagnosticBuilder::new(self, Level::Fatal, msg); result.set_span(sp); result.code(code.to_owned()); result } pub fn struct_fatal<'a>(&'a self, msg: &str) -> DiagnosticBuilder<'a> { - self.bump_err_count(); DiagnosticBuilder::new(self, Level::Fatal, msg) } pub fn cancel(&self, err: &mut DiagnosticBuilder) { - if err.level == Level::Error || err.level == Level::Fatal { - self.err_count.set( - self.err_count.get().checked_sub(1) - .expect("cancelled an error but err_count is 0") - ); - } err.cancel(); } @@ -558,23 +342,22 @@ impl Handler { } } - pub fn span_fatal>(&self, sp: S, msg: &str) - -> FatalError { + pub fn span_fatal>(&self, sp: S, msg: &str) -> FatalError { self.emit(&sp.into(), msg, Fatal); - self.bump_err_count(); self.panic_if_treat_err_as_bug(); return FatalError; } - pub fn span_fatal_with_code>(&self, sp: S, msg: &str, code: &str) + pub fn span_fatal_with_code>(&self, + sp: S, + msg: &str, + code: &str) -> FatalError { self.emit_with_code(&sp.into(), msg, code, Fatal); - self.bump_err_count(); self.panic_if_treat_err_as_bug(); return FatalError; } pub fn span_err>(&self, sp: S, msg: &str) { self.emit(&sp.into(), msg, Error); - self.bump_err_count(); self.panic_if_treat_err_as_bug(); } pub fn mut_span_err<'a, S: Into>(&'a self, @@ -583,12 +366,10 @@ impl Handler { -> DiagnosticBuilder<'a> { let mut result = DiagnosticBuilder::new(self, Level::Error, msg); result.set_span(sp); - self.bump_err_count(); result } pub fn span_err_with_code>(&self, sp: S, msg: &str, code: &str) { self.emit_with_code(&sp.into(), msg, code, Error); - self.bump_err_count(); self.panic_if_treat_err_as_bug(); } pub fn span_warn>(&self, sp: S, msg: &str) { @@ -607,7 +388,6 @@ impl Handler { } pub fn span_bug_no_panic>(&self, sp: S, msg: &str) { self.emit(&sp.into(), msg, Bug); - self.bump_err_count(); } pub fn span_note_without_error>(&self, sp: S, msg: &str) { self.emit(&sp.into(), msg, Note); @@ -619,39 +399,27 @@ impl Handler { if self.treat_err_as_bug { self.bug(msg); } - let mut db = DiagnosticBuilder::new(self, - Fatal, - msg); + let mut db = DiagnosticBuilder::new(self, Fatal, msg); db.emit(); - self.bump_err_count(); FatalError } pub fn err(&self, msg: &str) { if self.treat_err_as_bug { self.bug(msg); } - let mut db = DiagnosticBuilder::new(self, - Error, - msg); + let mut db = DiagnosticBuilder::new(self, Error, msg); db.emit(); - self.bump_err_count(); } pub fn warn(&self, msg: &str) { - let mut db = DiagnosticBuilder::new(self, - Warning, - msg); + let mut db = DiagnosticBuilder::new(self, Warning, msg); db.emit(); } pub fn note_without_error(&self, msg: &str) { - let mut db = DiagnosticBuilder::new(self, - Note, - msg); + let mut db = DiagnosticBuilder::new(self, Note, msg); db.emit(); } pub fn bug(&self, msg: &str) -> ! { - let mut db = DiagnosticBuilder::new(self, - Bug, - msg); + let mut db = DiagnosticBuilder::new(self, Bug, msg); db.emit(); panic!(ExplicitBug); } @@ -678,44 +446,41 @@ impl Handler { match *delayed_bug { Some((ref span, ref errmsg)) => { self.span_bug(span.clone(), errmsg); - }, + } _ => {} } return; } 1 => s = "aborting due to previous error".to_string(), - _ => { - s = format!("aborting due to {} previous errors", - self.err_count.get()); + _ => { + s = format!("aborting due to {} previous errors", self.err_count.get()); } } panic!(self.fatal(&s)); } - pub fn emit(&self, - msp: &MultiSpan, - msg: &str, - lvl: Level) { - if lvl == Warning && !self.can_emit_warnings { return } + pub fn emit(&self, msp: &MultiSpan, msg: &str, lvl: Level) { + if lvl == Warning && !self.can_emit_warnings { + return; + } let mut db = DiagnosticBuilder::new(self, lvl, msg); db.set_span(msp.clone()); db.emit(); - if !self.continue_after_error.get() { self.abort_if_errors(); } - } - pub fn emit_with_code(&self, - msp: &MultiSpan, - msg: &str, - code: &str, - lvl: Level) { - if lvl == Warning && !self.can_emit_warnings { return } - let mut db = DiagnosticBuilder::new_with_code(self, - lvl, - Some(code.to_owned()), - msg); + if !self.continue_after_error.get() { + self.abort_if_errors(); + } + } + pub fn emit_with_code(&self, msp: &MultiSpan, msg: &str, code: &str, lvl: Level) { + if lvl == Warning && !self.can_emit_warnings { + return; + } + let mut db = DiagnosticBuilder::new_with_code(self, lvl, Some(code.to_owned()), msg); db.set_span(msp.clone()); db.emit(); - if !self.continue_after_error.get() { self.abort_if_errors(); } + if !self.continue_after_error.get() { + self.abort_if_errors(); + } } } @@ -750,7 +515,7 @@ impl Level { } else { term::color::YELLOW } - }, + } Note => term::color::BRIGHT_GREEN, Help => term::color::BRIGHT_CYAN, Cancelled => unreachable!(), @@ -769,8 +534,8 @@ impl Level { } } -pub fn expect(diag: &Handler, opt: Option, msg: M) -> T where - M: FnOnce() -> String, +pub fn expect(diag: &Handler, opt: Option, msg: M) -> T + where M: FnOnce() -> String { match opt { Some(t) => t, diff --git a/src/librustc_errors/lock.rs b/src/librustc_errors/lock.rs index 0a9e0c4bbe..4c298228c3 100644 --- a/src/librustc_errors/lock.rs +++ b/src/librustc_errors/lock.rs @@ -40,9 +40,9 @@ pub fn acquire_global_lock(name: &str) -> Box { extern "system" { fn CreateMutexA(lpMutexAttributes: LPSECURITY_ATTRIBUTES, bInitialOwner: BOOL, - lpName: LPCSTR) -> HANDLE; - fn WaitForSingleObject(hHandle: HANDLE, - dwMilliseconds: DWORD) -> DWORD; + lpName: LPCSTR) + -> HANDLE; + fn WaitForSingleObject(hHandle: HANDLE, dwMilliseconds: DWORD) -> DWORD; fn ReleaseMutex(hMutex: HANDLE) -> BOOL; fn CloseHandle(hObject: HANDLE) -> BOOL; } @@ -76,7 +76,8 @@ pub fn acquire_global_lock(name: &str) -> Box { // open up a handle to one if it already exists. let mutex = CreateMutexA(0 as *mut _, 0, cname.as_ptr() as *const u8); if mutex.is_null() { - panic!("failed to create global mutex named `{}`: {}", name, + panic!("failed to create global mutex named `{}`: {}", + name, io::Error::last_os_error()); } let mutex = Handle(mutex); @@ -96,8 +97,10 @@ pub fn acquire_global_lock(name: &str) -> Box { WAIT_OBJECT_0 | WAIT_ABANDONED => {} code => { panic!("WaitForSingleObject failed on global mutex named \ - `{}`: {} (ret={:x})", name, - io::Error::last_os_error(), code); + `{}`: {} (ret={:x})", + name, + io::Error::last_os_error(), + code); } } diff --git a/src/librustc_errors/registry.rs b/src/librustc_errors/registry.rs index a6cfd1a5a9..8373768147 100644 --- a/src/librustc_errors/registry.rs +++ b/src/librustc_errors/registry.rs @@ -12,7 +12,7 @@ use std::collections::HashMap; #[derive(Clone)] pub struct Registry { - descriptions: HashMap<&'static str, &'static str> + descriptions: HashMap<&'static str, &'static str>, } impl Registry { diff --git a/src/librustc_errors/snippet.rs b/src/librustc_errors/snippet.rs index 5ade8cd9ba..abfb71c861 100644 --- a/src/librustc_errors/snippet.rs +++ b/src/librustc_errors/snippet.rs @@ -13,12 +13,12 @@ use syntax_pos::{Span, FileMap}; use CodeMapper; use std::rc::Rc; -use {Level}; +use Level; #[derive(Clone)] pub struct SnippetData { codemap: Rc, - files: Vec + files: Vec, } #[derive(Clone)] @@ -84,4 +84,4 @@ pub enum Style { NoStyle, ErrorCode, Level(Level), -} \ No newline at end of file +} diff --git a/src/librustc_errors/styled_buffer.rs b/src/librustc_errors/styled_buffer.rs index 9768b68619..dfc7c64de0 100644 --- a/src/librustc_errors/styled_buffer.rs +++ b/src/librustc_errors/styled_buffer.rs @@ -28,10 +28,9 @@ impl StyledBuffer { pub fn copy_tabs(&mut self, row: usize) { if row < self.text.len() { - for i in row+1..self.text.len() { + for i in row + 1..self.text.len() { for j in 0..self.text[i].len() { - if self.text[row].len() > j && - self.text[row][j] == '\t' && + if self.text[row].len() > j && self.text[row][j] == '\t' && self.text[i][j] == ' ' { self.text[i][j] = '\t'; } @@ -44,7 +43,7 @@ impl StyledBuffer { let mut output: Vec> = vec![]; let mut styled_vec: Vec = vec![]; - //before we render, do a little patch-up work to support tabs + // before we render, do a little patch-up work to support tabs self.copy_tabs(3); for (row, row_style) in self.text.iter().zip(&self.styles) { diff --git a/src/librustc_incremental/calculate_svh/hasher.rs b/src/librustc_incremental/calculate_svh/hasher.rs new file mode 100644 index 0000000000..d7d9c231a9 --- /dev/null +++ b/src/librustc_incremental/calculate_svh/hasher.rs @@ -0,0 +1,88 @@ +// Copyright 2016 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +use std::mem; +use std::hash::Hasher; +use rustc_data_structures::blake2b::Blake2bHasher; +use rustc::ty::util::ArchIndependentHasher; +use ich::Fingerprint; +use rustc_serialize::leb128::write_unsigned_leb128; + +#[derive(Debug)] +pub struct IchHasher { + state: ArchIndependentHasher, + leb128_helper: Vec, + bytes_hashed: u64, +} + +impl IchHasher { + pub fn new() -> IchHasher { + let hash_size = mem::size_of::(); + IchHasher { + state: ArchIndependentHasher::new(Blake2bHasher::new(hash_size, &[])), + leb128_helper: vec![], + bytes_hashed: 0 + } + } + + pub fn bytes_hashed(&self) -> u64 { + self.bytes_hashed + } + + pub fn finish(self) -> Fingerprint { + let mut fingerprint = Fingerprint::zero(); + fingerprint.0.copy_from_slice(self.state.into_inner().finalize()); + fingerprint + } + + #[inline] + fn write_uleb128(&mut self, value: u64) { + let len = write_unsigned_leb128(&mut self.leb128_helper, 0, value); + self.state.write(&self.leb128_helper[0..len]); + self.bytes_hashed += len as u64; + } +} + +// For the non-u8 integer cases we leb128 encode them first. Because small +// integers dominate, this significantly and cheaply reduces the number of +// bytes hashed, which is good because blake2b is expensive. +impl Hasher for IchHasher { + fn finish(&self) -> u64 { + bug!("Use other finish() implementation to get the full 128-bit hash."); + } + + #[inline] + fn write(&mut self, bytes: &[u8]) { + self.state.write(bytes); + self.bytes_hashed += bytes.len() as u64; + } + + // There is no need to leb128-encode u8 values. + + #[inline] + fn write_u16(&mut self, i: u16) { + self.write_uleb128(i as u64); + } + + #[inline] + fn write_u32(&mut self, i: u32) { + self.write_uleb128(i as u64); + } + + #[inline] + fn write_u64(&mut self, i: u64) { + self.write_uleb128(i); + } + + #[inline] + fn write_usize(&mut self, i: usize) { + self.write_uleb128(i as u64); + } +} diff --git a/src/librustc_incremental/calculate_svh/mod.rs b/src/librustc_incremental/calculate_svh/mod.rs index a22b51ac04..3b0b37bb01 100644 --- a/src/librustc_incremental/calculate_svh/mod.rs +++ b/src/librustc_incremental/calculate_svh/mod.rs @@ -29,8 +29,7 @@ use syntax::ast; use std::cell::RefCell; -use std::hash::{Hash, Hasher}; -use std::collections::hash_map::DefaultHasher; +use std::hash::Hash; use rustc::dep_graph::DepNode; use rustc::hir; use rustc::hir::def_id::{CRATE_DEF_INDEX, DefId}; @@ -43,20 +42,23 @@ use rustc::session::config::DebugInfoLevel::NoDebugInfo; use self::def_path_hash::DefPathHashes; use self::svh_visitor::StrictVersionHashVisitor; use self::caching_codemap_view::CachingCodemapView; +use self::hasher::IchHasher; +use ich::Fingerprint; mod def_path_hash; mod svh_visitor; mod caching_codemap_view; +pub mod hasher; pub struct IncrementalHashesMap { - hashes: FnvHashMap, u64>, + hashes: FnvHashMap, Fingerprint>, // These are the metadata hashes for the current crate as they were stored // during the last compilation session. They are only loaded if // -Z query-dep-graph was specified and are needed for auto-tests using // the #[rustc_metadata_dirty] and #[rustc_metadata_clean] attributes to // check whether some metadata hash has changed in between two revisions. - pub prev_metadata_hashes: RefCell>, + pub prev_metadata_hashes: RefCell>, } impl IncrementalHashesMap { @@ -67,19 +69,24 @@ impl IncrementalHashesMap { } } - pub fn insert(&mut self, k: DepNode, v: u64) -> Option { + pub fn insert(&mut self, k: DepNode, v: Fingerprint) -> Option { self.hashes.insert(k, v) } - pub fn iter<'a>(&'a self) -> ::std::collections::hash_map::Iter<'a, DepNode, u64> { + pub fn iter<'a>(&'a self) + -> ::std::collections::hash_map::Iter<'a, DepNode, Fingerprint> { self.hashes.iter() } + + pub fn len(&self) -> usize { + self.hashes.len() + } } impl<'a> ::std::ops::Index<&'a DepNode> for IncrementalHashesMap { - type Output = u64; + type Output = Fingerprint; - fn index(&self, index: &'a DepNode) -> &u64 { + fn index(&self, index: &'a DepNode) -> &Fingerprint { &self.hashes[index] } } @@ -102,6 +109,9 @@ pub fn compute_incremental_hashes_map<'a, 'tcx: 'a>(tcx: TyCtxt<'a, 'tcx, 'tcx>) |v| visit::walk_crate(v, krate)); krate.visit_all_items(&mut visitor); }); + + tcx.sess.perf_stats.incr_comp_hashes_count.set(visitor.hashes.len() as u64); + record_time(&tcx.sess.perf_stats.svh_time, || visitor.compute_crate_hash()); visitor.hashes } @@ -127,23 +137,26 @@ impl<'a, 'tcx> HashItemsVisitor<'a, 'tcx> { { assert!(def_id.is_local()); debug!("HashItemsVisitor::calculate(def_id={:?})", def_id); - // FIXME: this should use SHA1, not DefaultHasher. DefaultHasher is not - // built to avoid collisions. - let mut state = DefaultHasher::new(); + let mut state = IchHasher::new(); walk_op(&mut StrictVersionHashVisitor::new(&mut state, self.tcx, &mut self.def_path_hashes, &mut self.codemap, self.hash_spans)); + let bytes_hashed = state.bytes_hashed(); let item_hash = state.finish(); self.hashes.insert(DepNode::Hir(def_id), item_hash); debug!("calculate_item_hash: def_id={:?} hash={:?}", def_id, item_hash); + + let bytes_hashed = self.tcx.sess.perf_stats.incr_comp_bytes_hashed.get() + + bytes_hashed; + self.tcx.sess.perf_stats.incr_comp_bytes_hashed.set(bytes_hashed); } fn compute_crate_hash(&mut self) { let krate = self.tcx.map.krate(); - let mut crate_state = DefaultHasher::new(); + let mut crate_state = IchHasher::new(); let crate_disambiguator = self.tcx.sess.local_crate_disambiguator(); "crate_disambiguator".hash(&mut crate_state); diff --git a/src/librustc_incremental/calculate_svh/svh_visitor.rs b/src/librustc_incremental/calculate_svh/svh_visitor.rs index 0cd5ae6845..2358d60d0d 100644 --- a/src/librustc_incremental/calculate_svh/svh_visitor.rs +++ b/src/librustc_incremental/calculate_svh/svh_visitor.rs @@ -15,7 +15,13 @@ use self::SawExprComponent::*; use self::SawAbiComponent::*; +use self::SawItemComponent::*; +use self::SawPatComponent::*; +use self::SawTyComponent::*; +use self::SawTraitOrImplItemComponent::*; +use syntax::abi::Abi; use syntax::ast::{self, Name, NodeId}; +use syntax::attr; use syntax::parse::token; use syntax_pos::{Span, NO_EXPANSION, COMMAND_LINE_EXPN, BytePos}; use rustc::hir; @@ -26,10 +32,10 @@ use rustc::hir::intravisit as visit; use rustc::ty::TyCtxt; use rustc_data_structures::fnv; use std::hash::Hash; -use std::collections::hash_map::DefaultHasher; use super::def_path_hash::DefPathHashes; use super::caching_codemap_view::CachingCodemapView; +use super::hasher::IchHasher; const IGNORED_ATTRIBUTES: &'static [&'static str] = &[ "cfg", @@ -43,26 +49,31 @@ const IGNORED_ATTRIBUTES: &'static [&'static str] = &[ pub struct StrictVersionHashVisitor<'a, 'hash: 'a, 'tcx: 'hash> { pub tcx: TyCtxt<'hash, 'tcx, 'tcx>, - pub st: &'a mut DefaultHasher, + pub st: &'a mut IchHasher, // collect a deterministic hash of def-ids that we have seen def_path_hashes: &'a mut DefPathHashes<'hash, 'tcx>, hash_spans: bool, codemap: &'a mut CachingCodemapView<'tcx>, + overflow_checks_enabled: bool, } impl<'a, 'hash, 'tcx> StrictVersionHashVisitor<'a, 'hash, 'tcx> { - pub fn new(st: &'a mut DefaultHasher, + pub fn new(st: &'a mut IchHasher, tcx: TyCtxt<'hash, 'tcx, 'tcx>, def_path_hashes: &'a mut DefPathHashes<'hash, 'tcx>, codemap: &'a mut CachingCodemapView<'tcx>, hash_spans: bool) -> Self { + let check_overflow = tcx.sess.opts.debugging_opts.force_overflow_checks + .unwrap_or(tcx.sess.opts.debug_assertions); + StrictVersionHashVisitor { st: st, tcx: tcx, def_path_hashes: def_path_hashes, hash_spans: hash_spans, codemap: codemap, + overflow_checks_enabled: check_overflow, } } @@ -77,8 +88,9 @@ impl<'a, 'hash, 'tcx> StrictVersionHashVisitor<'a, 'hash, 'tcx> { // within the CodeMap. // Also note that we are hashing byte offsets for the column, not unicode // codepoint offsets. For the purpose of the hash that's sufficient. + // Also, hashing filenames is expensive so we avoid doing it twice when the + // span starts and ends in the same file, which is almost always the case. fn hash_span(&mut self, span: Span) { - debug_assert!(self.hash_spans); debug!("hash_span: st={:?}", self.st); // If this is not an empty or invalid span, we want to hash the last @@ -93,21 +105,35 @@ impl<'a, 'hash, 'tcx> StrictVersionHashVisitor<'a, 'hash, 'tcx> { span.hi }; - let loc1 = self.codemap.byte_pos_to_line_and_col(span.lo); - let loc2 = self.codemap.byte_pos_to_line_and_col(span_hi); - - let expansion_kind = match span.expn_id { + let expn_kind = match span.expn_id { NO_EXPANSION => SawSpanExpnKind::NoExpansion, COMMAND_LINE_EXPN => SawSpanExpnKind::CommandLine, _ => SawSpanExpnKind::SomeExpansion, }; - SawSpan(loc1.as_ref().map(|&(ref fm, line, col)| (&fm.name[..], line, col)), - loc2.as_ref().map(|&(ref fm, line, col)| (&fm.name[..], line, col)), - expansion_kind) - .hash(self.st); + let loc1 = self.codemap.byte_pos_to_line_and_col(span.lo); + let loc1 = loc1.as_ref() + .map(|&(ref fm, line, col)| (&fm.name[..], line, col)) + .unwrap_or(("???", 0, BytePos(0))); - if expansion_kind == SawSpanExpnKind::SomeExpansion { + let loc2 = self.codemap.byte_pos_to_line_and_col(span_hi); + let loc2 = loc2.as_ref() + .map(|&(ref fm, line, col)| (&fm.name[..], line, col)) + .unwrap_or(("???", 0, BytePos(0))); + + let saw = if loc1.0 == loc2.0 { + SawSpan(loc1.0, + loc1.1, loc1.2, + loc2.1, loc2.2, + expn_kind) + } else { + SawSpanTwoFiles(loc1.0, loc1.1, loc1.2, + loc2.0, loc2.1, loc2.2, + expn_kind) + }; + saw.hash(self.st); + + if expn_kind == SawSpanExpnKind::SomeExpansion { let call_site = self.codemap.codemap().source_callsite(span); self.hash_span(call_site); } @@ -155,11 +181,11 @@ enum SawAbiComponent<'a> { SawMod, SawForeignItem, - SawItem, - SawTy, + SawItem(SawItemComponent), + SawTy(SawTyComponent), SawGenerics, - SawTraitItem, - SawImplItem, + SawTraitItem(SawTraitOrImplItemComponent), + SawImplItem(SawTraitOrImplItemComponent), SawStructField, SawVariant, SawPath(bool), @@ -167,7 +193,7 @@ enum SawAbiComponent<'a> { SawPathParameters, SawPathListItem, SawBlock, - SawPat, + SawPat(SawPatComponent), SawLocal, SawArm, SawExpr(SawExprComponent<'a>), @@ -179,9 +205,13 @@ enum SawAbiComponent<'a> { SawAssocTypeBinding, SawAttribute(ast::AttrStyle), SawMacroDef, - SawSpan(Option<(&'a str, usize, BytePos)>, - Option<(&'a str, usize, BytePos)>, + SawSpan(&'a str, + usize, BytePos, + usize, BytePos, SawSpanExpnKind), + SawSpanTwoFiles(&'a str, usize, BytePos, + &'a str, usize, BytePos, + SawSpanExpnKind), } /// SawExprComponent carries all of the information that we want @@ -198,6 +228,9 @@ enum SawAbiComponent<'a> { /// because the SVH is just a developer convenience; there is no /// guarantee of collision-freedom, hash collisions are just /// (hopefully) unlikely.) +/// +/// The xxxComponent enums and saw_xxx functions for Item, Pat, +/// Ty, TraitItem and ImplItem follow the same methodology. #[derive(Hash)] enum SawExprComponent<'a> { @@ -208,7 +241,7 @@ enum SawExprComponent<'a> { SawExprAgain(Option), SawExprBox, - SawExprVec, + SawExprArray, SawExprCall, SawExprMethodCall, SawExprTup, @@ -233,37 +266,208 @@ enum SawExprComponent<'a> { SawExprRepeat, } -fn saw_expr<'a>(node: &'a Expr_) -> SawExprComponent<'a> { +// The boolean returned indicates whether the span of this expression is always +// significant, regardless of debuginfo. +fn saw_expr<'a>(node: &'a Expr_, + overflow_checks_enabled: bool) + -> (SawExprComponent<'a>, bool) { + let binop_can_panic_at_runtime = |binop| { + match binop { + BiAdd | + BiSub | + BiMul => overflow_checks_enabled, + + BiDiv | + BiRem => true, + + BiAnd | + BiOr | + BiBitXor | + BiBitAnd | + BiBitOr | + BiShl | + BiShr | + BiEq | + BiLt | + BiLe | + BiNe | + BiGe | + BiGt => false + } + }; + + let unop_can_panic_at_runtime = |unop| { + match unop { + UnDeref | + UnNot => false, + UnNeg => overflow_checks_enabled, + } + }; + match *node { - ExprBox(..) => SawExprBox, - ExprVec(..) => SawExprVec, - ExprCall(..) => SawExprCall, - ExprMethodCall(..) => SawExprMethodCall, - ExprTup(..) => SawExprTup, - ExprBinary(op, ..) => SawExprBinary(op.node), - ExprUnary(op, _) => SawExprUnary(op), - ExprLit(ref lit) => SawExprLit(lit.node.clone()), - ExprCast(..) => SawExprCast, - ExprType(..) => SawExprType, - ExprIf(..) => SawExprIf, - ExprWhile(..) => SawExprWhile, - ExprLoop(_, id) => SawExprLoop(id.map(|id| id.node.as_str())), - ExprMatch(..) => SawExprMatch, - ExprClosure(cc, _, _, _) => SawExprClosure(cc), - ExprBlock(..) => SawExprBlock, - ExprAssign(..) => SawExprAssign, - ExprAssignOp(op, ..) => SawExprAssignOp(op.node), - ExprField(_, name) => SawExprField(name.node.as_str()), - ExprTupField(_, id) => SawExprTupField(id.node), - ExprIndex(..) => SawExprIndex, - ExprPath(ref qself, _) => SawExprPath(qself.as_ref().map(|q| q.position)), - ExprAddrOf(m, _) => SawExprAddrOf(m), - ExprBreak(id) => SawExprBreak(id.map(|id| id.node.as_str())), - ExprAgain(id) => SawExprAgain(id.map(|id| id.node.as_str())), - ExprRet(..) => SawExprRet, - ExprInlineAsm(ref a,..) => SawExprInlineAsm(a), - ExprStruct(..) => SawExprStruct, - ExprRepeat(..) => SawExprRepeat, + ExprBox(..) => (SawExprBox, false), + ExprArray(..) => (SawExprArray, false), + ExprCall(..) => (SawExprCall, false), + ExprMethodCall(..) => (SawExprMethodCall, false), + ExprTup(..) => (SawExprTup, false), + ExprBinary(op, ..) => { + (SawExprBinary(op.node), binop_can_panic_at_runtime(op.node)) + } + ExprUnary(op, _) => { + (SawExprUnary(op), unop_can_panic_at_runtime(op)) + } + ExprLit(ref lit) => (SawExprLit(lit.node.clone()), false), + ExprCast(..) => (SawExprCast, false), + ExprType(..) => (SawExprType, false), + ExprIf(..) => (SawExprIf, false), + ExprWhile(..) => (SawExprWhile, false), + ExprLoop(_, id) => (SawExprLoop(id.map(|id| id.node.as_str())), false), + ExprMatch(..) => (SawExprMatch, false), + ExprClosure(cc, _, _, _) => (SawExprClosure(cc), false), + ExprBlock(..) => (SawExprBlock, false), + ExprAssign(..) => (SawExprAssign, false), + ExprAssignOp(op, ..) => { + (SawExprAssignOp(op.node), binop_can_panic_at_runtime(op.node)) + } + ExprField(_, name) => (SawExprField(name.node.as_str()), false), + ExprTupField(_, id) => (SawExprTupField(id.node), false), + ExprIndex(..) => (SawExprIndex, true), + ExprPath(ref qself, _) => (SawExprPath(qself.as_ref().map(|q| q.position)), false), + ExprAddrOf(m, _) => (SawExprAddrOf(m), false), + ExprBreak(id) => (SawExprBreak(id.map(|id| id.node.as_str())), false), + ExprAgain(id) => (SawExprAgain(id.map(|id| id.node.as_str())), false), + ExprRet(..) => (SawExprRet, false), + ExprInlineAsm(ref a,..) => (SawExprInlineAsm(a), false), + ExprStruct(..) => (SawExprStruct, false), + ExprRepeat(..) => (SawExprRepeat, false), + } +} + +#[derive(Hash)] +enum SawItemComponent { + SawItemExternCrate, + SawItemUse, + SawItemStatic(Mutability), + SawItemConst, + SawItemFn(Unsafety, Constness, Abi), + SawItemMod, + SawItemForeignMod, + SawItemTy, + SawItemEnum, + SawItemStruct, + SawItemUnion, + SawItemTrait(Unsafety), + SawItemDefaultImpl(Unsafety), + SawItemImpl(Unsafety, ImplPolarity) +} + +fn saw_item(node: &Item_) -> SawItemComponent { + match *node { + ItemExternCrate(..) => SawItemExternCrate, + ItemUse(..) => SawItemUse, + ItemStatic(_, mutability, _) => SawItemStatic(mutability), + ItemConst(..) =>SawItemConst, + ItemFn(_, unsafety, constness, abi, _, _) => SawItemFn(unsafety, constness, abi), + ItemMod(..) => SawItemMod, + ItemForeignMod(..) => SawItemForeignMod, + ItemTy(..) => SawItemTy, + ItemEnum(..) => SawItemEnum, + ItemStruct(..) => SawItemStruct, + ItemUnion(..) => SawItemUnion, + ItemTrait(unsafety, ..) => SawItemTrait(unsafety), + ItemDefaultImpl(unsafety, _) => SawItemDefaultImpl(unsafety), + ItemImpl(unsafety, implpolarity, ..) => SawItemImpl(unsafety, implpolarity) + } +} + +#[derive(Hash)] +enum SawPatComponent { + SawPatWild, + SawPatBinding(BindingMode), + SawPatStruct, + SawPatTupleStruct, + SawPatPath, + SawPatTuple, + SawPatBox, + SawPatRef(Mutability), + SawPatLit, + SawPatRange, + SawPatSlice +} + +fn saw_pat(node: &PatKind) -> SawPatComponent { + match *node { + PatKind::Wild => SawPatWild, + PatKind::Binding(bindingmode, ..) => SawPatBinding(bindingmode), + PatKind::Struct(..) => SawPatStruct, + PatKind::TupleStruct(..) => SawPatTupleStruct, + PatKind::Path(..) => SawPatPath, + PatKind::Tuple(..) => SawPatTuple, + PatKind::Box(..) => SawPatBox, + PatKind::Ref(_, mutability) => SawPatRef(mutability), + PatKind::Lit(..) => SawPatLit, + PatKind::Range(..) => SawPatRange, + PatKind::Slice(..) => SawPatSlice + } +} + +#[derive(Hash)] +enum SawTyComponent { + SawTySlice, + SawTyArray, + SawTyPtr(Mutability), + SawTyRptr(Mutability), + SawTyBareFn(Unsafety, Abi), + SawTyNever, + SawTyTup, + SawTyPath, + SawTyObjectSum, + SawTyPolyTraitRef, + SawTyImplTrait, + SawTyTypeof, + SawTyInfer +} + +fn saw_ty(node: &Ty_) -> SawTyComponent { + match *node { + TySlice(..) => SawTySlice, + TyArray(..) => SawTyArray, + TyPtr(ref mty) => SawTyPtr(mty.mutbl), + TyRptr(_, ref mty) => SawTyRptr(mty.mutbl), + TyBareFn(ref barefnty) => SawTyBareFn(barefnty.unsafety, barefnty.abi), + TyNever => SawTyNever, + TyTup(..) => SawTyTup, + TyPath(..) => SawTyPath, + TyObjectSum(..) => SawTyObjectSum, + TyPolyTraitRef(..) => SawTyPolyTraitRef, + TyImplTrait(..) => SawTyImplTrait, + TyTypeof(..) => SawTyTypeof, + TyInfer => SawTyInfer + } +} + +#[derive(Hash)] +enum SawTraitOrImplItemComponent { + SawTraitOrImplItemConst, + SawTraitOrImplItemMethod(Unsafety, Constness, Abi), + SawTraitOrImplItemType +} + +fn saw_trait_item(ti: &TraitItem_) -> SawTraitOrImplItemComponent { + match *ti { + ConstTraitItem(..) => SawTraitOrImplItemConst, + MethodTraitItem(ref sig, _) => + SawTraitOrImplItemMethod(sig.unsafety, sig.constness, sig.abi), + TypeTraitItem(..) => SawTraitOrImplItemType + } +} + +fn saw_impl_item(ii: &ImplItemKind) -> SawTraitOrImplItemComponent { + match *ii { + ImplItemKind::Const(..) => SawTraitOrImplItemConst, + ImplItemKind::Method(ref sig, _) => + SawTraitOrImplItemMethod(sig.unsafety, sig.constness, sig.abi), + ImplItemKind::Type(..) => SawTraitOrImplItemType } } @@ -285,10 +489,13 @@ macro_rules! hash_attrs { macro_rules! hash_span { ($visitor:expr, $span:expr) => ({ - if $visitor.hash_spans { + hash_span!($visitor, $span, false) + }); + ($visitor:expr, $span:expr, $force:expr) => ({ + if $force || $visitor.hash_spans { $visitor.hash_span($span); } - }) + }); } impl<'a, 'hash, 'tcx> visit::Visitor<'tcx> for StrictVersionHashVisitor<'a, 'hash, 'tcx> { @@ -338,10 +545,12 @@ impl<'a, 'hash, 'tcx> visit::Visitor<'tcx> for StrictVersionHashVisitor<'a, 'has fn visit_expr(&mut self, ex: &'tcx Expr) { debug!("visit_expr: st={:?}", self.st); - SawExpr(saw_expr(&ex.node)).hash(self.st); + let (saw_expr, force_span) = saw_expr(&ex.node, + self.overflow_checks_enabled); + SawExpr(saw_expr).hash(self.st); // No need to explicitly hash the discriminant here, since we are // implicitly hashing the discriminant of SawExprComponent. - hash_span!(self, ex.span); + hash_span!(self, ex.span, force_span); hash_attrs!(self, &ex.attrs); visit::walk_expr(self, ex) } @@ -384,9 +593,9 @@ impl<'a, 'hash, 'tcx> visit::Visitor<'tcx> for StrictVersionHashVisitor<'a, 'has fn visit_item(&mut self, i: &'tcx Item) { debug!("visit_item: {:?} st={:?}", i, self.st); - SawItem.hash(self.st); - // Hash the value of the discriminant of the Item variant. - self.hash_discriminant(&i.node); + self.maybe_enable_overflow_checks(&i.attrs); + + SawItem(saw_item(&i.node)).hash(self.st); hash_span!(self, i.span); hash_attrs!(self, &i.attrs); visit::walk_item(self, i) @@ -399,7 +608,7 @@ impl<'a, 'hash, 'tcx> visit::Visitor<'tcx> for StrictVersionHashVisitor<'a, 'has fn visit_ty(&mut self, t: &'tcx Ty) { debug!("visit_ty: st={:?}", self.st); - SawTy.hash(self.st); + SawTy(saw_ty(&t.node)).hash(self.st); hash_span!(self, t.span); visit::walk_ty(self, t) } @@ -412,8 +621,10 @@ impl<'a, 'hash, 'tcx> visit::Visitor<'tcx> for StrictVersionHashVisitor<'a, 'has fn visit_trait_item(&mut self, ti: &'tcx TraitItem) { debug!("visit_trait_item: st={:?}", self.st); - SawTraitItem.hash(self.st); - self.hash_discriminant(&ti.node); + + self.maybe_enable_overflow_checks(&ti.attrs); + + SawTraitItem(saw_trait_item(&ti.node)).hash(self.st); hash_span!(self, ti.span); hash_attrs!(self, &ti.attrs); visit::walk_trait_item(self, ti) @@ -421,8 +632,10 @@ impl<'a, 'hash, 'tcx> visit::Visitor<'tcx> for StrictVersionHashVisitor<'a, 'has fn visit_impl_item(&mut self, ii: &'tcx ImplItem) { debug!("visit_impl_item: st={:?}", self.st); - SawImplItem.hash(self.st); - self.hash_discriminant(&ii.node); + + self.maybe_enable_overflow_checks(&ii.attrs); + + SawImplItem(saw_impl_item(&ii.node)).hash(self.st); hash_span!(self, ii.span); hash_attrs!(self, &ii.attrs); visit::walk_impl_item(self, ii) @@ -452,8 +665,7 @@ impl<'a, 'hash, 'tcx> visit::Visitor<'tcx> for StrictVersionHashVisitor<'a, 'has fn visit_pat(&mut self, p: &'tcx Pat) { debug!("visit_pat: st={:?}", self.st); - SawPat.hash(self.st); - self.hash_discriminant(&p.node); + SawPat(saw_pat(&p.node)).hash(self.st); hash_span!(self, p.span); visit::walk_pat(self, p) } @@ -545,13 +757,11 @@ impl<'a, 'hash, 'tcx> visit::Visitor<'tcx> for StrictVersionHashVisitor<'a, 'has fn visit_macro_def(&mut self, macro_def: &'tcx MacroDef) { debug!("visit_macro_def: st={:?}", self.st); - if macro_def.export { - SawMacroDef.hash(self.st); - hash_attrs!(self, ¯o_def.attrs); - visit::walk_macro_def(self, macro_def) - // FIXME(mw): We should hash the body of the macro too but we don't - // have a stable way of doing so yet. - } + SawMacroDef.hash(self.st); + hash_attrs!(self, ¯o_def.attrs); + visit::walk_macro_def(self, macro_def) + // FIXME(mw): We should hash the body of the macro too but we don't + // have a stable way of doing so yet. } } @@ -611,11 +821,13 @@ impl<'a, 'hash, 'tcx> StrictVersionHashVisitor<'a, 'hash, 'tcx> { Def::Mod(..) | Def::Static(..) | Def::Variant(..) | + Def::VariantCtor(..) | Def::Enum(..) | Def::TyAlias(..) | Def::AssociatedTy(..) | Def::TyParam(..) | Def::Struct(..) | + Def::StructCtor(..) | Def::Union(..) | Def::Trait(..) | Def::Method(..) | @@ -712,4 +924,10 @@ impl<'a, 'hash, 'tcx> StrictVersionHashVisitor<'a, 'hash, 'tcx> { indices.sort_by_key(|index| get_key(&items[*index])); indices } + + fn maybe_enable_overflow_checks(&mut self, item_attrs: &[ast::Attribute]) { + if attr::contains_name(item_attrs, "rustc_inherit_overflow_checks") { + self.overflow_checks_enabled = true; + } + } } diff --git a/src/librustc_incremental/ich/fingerprint.rs b/src/librustc_incremental/ich/fingerprint.rs new file mode 100644 index 0000000000..005ac3896c --- /dev/null +++ b/src/librustc_incremental/ich/fingerprint.rs @@ -0,0 +1,81 @@ +// Copyright 2016 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +use rustc_serialize::{Encodable, Decodable, Encoder, Decoder}; + +const FINGERPRINT_LENGTH: usize = 16; + +#[derive(Eq, PartialEq, Ord, PartialOrd, Hash, Debug, Clone, Copy)] +pub struct Fingerprint(pub [u8; FINGERPRINT_LENGTH]); + +impl Fingerprint { + #[inline] + pub fn zero() -> Fingerprint { + Fingerprint([0; FINGERPRINT_LENGTH]) + } + + pub fn from_smaller_hash(hash: u64) -> Fingerprint { + let mut result = Fingerprint::zero(); + result.0[0] = (hash >> 0) as u8; + result.0[1] = (hash >> 8) as u8; + result.0[2] = (hash >> 16) as u8; + result.0[3] = (hash >> 24) as u8; + result.0[4] = (hash >> 32) as u8; + result.0[5] = (hash >> 40) as u8; + result.0[6] = (hash >> 48) as u8; + result.0[7] = (hash >> 56) as u8; + result + } + + pub fn to_smaller_hash(&self) -> u64 { + ((self.0[0] as u64) << 0) | + ((self.0[1] as u64) << 8) | + ((self.0[2] as u64) << 16) | + ((self.0[3] as u64) << 24) | + ((self.0[4] as u64) << 32) | + ((self.0[5] as u64) << 40) | + ((self.0[6] as u64) << 48) | + ((self.0[7] as u64) << 56) + } +} + +impl Encodable for Fingerprint { + #[inline] + fn encode(&self, s: &mut S) -> Result<(), S::Error> { + for &byte in &self.0[..] { + s.emit_u8(byte)?; + } + Ok(()) + } +} + +impl Decodable for Fingerprint { + #[inline] + fn decode(d: &mut D) -> Result { + let mut result = Fingerprint([0u8; FINGERPRINT_LENGTH]); + for byte in &mut result.0[..] { + *byte = d.read_u8()?; + } + Ok(result) + } +} + +impl ::std::fmt::Display for Fingerprint { + fn fmt(&self, formatter: &mut ::std::fmt::Formatter) -> Result<(), ::std::fmt::Error> { + for i in 0 .. self.0.len() { + if i > 0 { + write!(formatter, "::")?; + } + + write!(formatter, "{}", self.0[i])?; + } + Ok(()) + } +} diff --git a/src/librustc_incremental/ich/mod.rs b/src/librustc_incremental/ich/mod.rs new file mode 100644 index 0000000000..8edd04322d --- /dev/null +++ b/src/librustc_incremental/ich/mod.rs @@ -0,0 +1,13 @@ +// Copyright 2016 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +pub use self::fingerprint::Fingerprint; + +mod fingerprint; diff --git a/src/librustc_incremental/lib.rs b/src/librustc_incremental/lib.rs index 67104e912f..4a5a6b9bea 100644 --- a/src/librustc_incremental/lib.rs +++ b/src/librustc_incremental/lib.rs @@ -19,7 +19,7 @@ html_root_url = "https://doc.rust-lang.org/nightly/")] #![cfg_attr(not(stage0), deny(warnings))] -#![feature(dotdot_in_tuple_patterns)] +#![cfg_attr(stage0, feature(dotdot_in_tuple_patterns))] #![cfg_attr(stage0, feature(question_mark))] #![feature(rustc_private)] #![feature(staged_api)] @@ -45,6 +45,7 @@ const ATTR_THEN_THIS_WOULD_NEED: &'static str = "rustc_then_this_would_need"; mod assert_dep_graph; mod calculate_svh; mod persist; +pub mod ich; pub use assert_dep_graph::assert_dep_graph; pub use calculate_svh::compute_incremental_hashes_map; diff --git a/src/librustc_incremental/persist/data.rs b/src/librustc_incremental/persist/data.rs index 57e7a0bc21..734ffe6a94 100644 --- a/src/librustc_incremental/persist/data.rs +++ b/src/librustc_incremental/persist/data.rs @@ -14,6 +14,7 @@ use rustc::dep_graph::{DepNode, WorkProduct, WorkProductId}; use rustc::hir::def_id::DefIndex; use std::sync::Arc; use rustc_data_structures::fnv::FnvHashMap; +use ich::Fingerprint; use super::directory::DefPathIndex; @@ -60,7 +61,7 @@ pub struct SerializedHash { /// the hash as of previous compilation, computed by code in /// `hash` module - pub hash: u64, + pub hash: Fingerprint, } #[derive(Debug, RustcEncodable, RustcDecodable)] @@ -116,5 +117,5 @@ pub struct SerializedMetadataHash { pub def_index: DefIndex, /// the hash itself, computed by `calculate_item_hash` - pub hash: u64, + pub hash: Fingerprint, } diff --git a/src/librustc_incremental/persist/directory.rs b/src/librustc_incremental/persist/directory.rs index 619e237ee3..d238121872 100644 --- a/src/librustc_incremental/persist/directory.rs +++ b/src/librustc_incremental/persist/directory.rs @@ -20,6 +20,7 @@ use rustc::ty::TyCtxt; use rustc::util::nodemap::DefIdMap; use std::fmt::{self, Debug}; use std::iter::once; +use std::collections::HashMap; /// Index into the DefIdDirectory #[derive(Copy, Clone, Debug, PartialOrd, Ord, Hash, PartialEq, Eq, @@ -90,18 +91,29 @@ impl DefIdDirectory { } pub fn retrace(&self, tcx: TyCtxt) -> RetracedDefIdDirectory { - let max_current_crate = self.max_current_crate(tcx); + + fn make_key(name: &str, disambiguator: &str) -> String { + format!("{}/{}", name, disambiguator) + } + + let new_krates: HashMap<_, _> = + once(LOCAL_CRATE) + .chain(tcx.sess.cstore.crates()) + .map(|krate| (make_key(&tcx.crate_name(krate), + &tcx.crate_disambiguator(krate)), krate)) + .collect(); let ids = self.paths.iter() .map(|path| { - if self.krate_still_valid(tcx, max_current_crate, path.krate) { - tcx.retrace_path(path) + let old_krate_id = path.krate.as_usize(); + assert!(old_krate_id < self.krates.len()); + let old_crate_info = &self.krates[old_krate_id]; + let old_crate_key = make_key(&old_crate_info.name, + &old_crate_info.disambiguator); + if let Some(&new_crate_key) = new_krates.get(&old_crate_key) { + tcx.retrace_path(new_crate_key, &path.data) } else { - debug!("crate {} changed from {:?} to {:?}/{:?}", - path.krate, - self.krates[path.krate.as_usize()], - tcx.crate_name(path.krate), - tcx.crate_disambiguator(path.krate)); + debug!("crate {:?} no longer exists", old_crate_key); None } }) diff --git a/src/librustc_incremental/persist/dirty_clean.rs b/src/librustc_incremental/persist/dirty_clean.rs index 95452021d8..94478f6603 100644 --- a/src/librustc_incremental/persist/dirty_clean.rs +++ b/src/librustc_incremental/persist/dirty_clean.rs @@ -51,6 +51,7 @@ use rustc_data_structures::fnv::{FnvHashSet, FnvHashMap}; use syntax::parse::token::InternedString; use syntax_pos::Span; use rustc::ty::TyCtxt; +use ich::Fingerprint; use {ATTR_DIRTY, ATTR_CLEAN, ATTR_DIRTY_METADATA, ATTR_CLEAN_METADATA}; @@ -186,8 +187,8 @@ impl<'a, 'tcx> Visitor<'tcx> for DirtyCleanVisitor<'a, 'tcx> { } pub fn check_dirty_clean_metadata<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, - prev_metadata_hashes: &FnvHashMap, - current_metadata_hashes: &FnvHashMap) { + prev_metadata_hashes: &FnvHashMap, + current_metadata_hashes: &FnvHashMap) { if !tcx.sess.opts.debugging_opts.query_dep_graph { return; } @@ -204,8 +205,8 @@ pub fn check_dirty_clean_metadata<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, pub struct DirtyCleanMetadataVisitor<'a, 'tcx:'a, 'm> { tcx: TyCtxt<'a, 'tcx, 'tcx>, - prev_metadata_hashes: &'m FnvHashMap, - current_metadata_hashes: &'m FnvHashMap, + prev_metadata_hashes: &'m FnvHashMap, + current_metadata_hashes: &'m FnvHashMap, } impl<'a, 'tcx, 'm> Visitor<'tcx> for DirtyCleanMetadataVisitor<'a, 'tcx, 'm> { @@ -263,7 +264,7 @@ impl<'a, 'tcx, 'm> DirtyCleanMetadataVisitor<'a, 'tcx, 'm> { /// flag called `foo`. fn check_config(tcx: TyCtxt, attr: &ast::Attribute) -> bool { debug!("check_config(attr={:?})", attr); - let config = &tcx.map.krate().config; + let config = &tcx.sess.parse_sess.config; debug!("check_config: config={:?}", config); for item in attr.meta_item_list().unwrap_or(&[]) { if item.check_name(CFG) { diff --git a/src/librustc_incremental/persist/fs.rs b/src/librustc_incremental/persist/fs.rs index 428283309b..ff7c3d0512 100644 --- a/src/librustc_incremental/persist/fs.rs +++ b/src/librustc_incremental/persist/fs.rs @@ -234,10 +234,21 @@ pub fn prepare_session_directory(tcx: TyCtxt) -> Result { let print_file_copy_stats = tcx.sess.opts.debugging_opts.incremental_info; // Try copying over all files from the source directory - if copy_files(&session_dir, &source_directory, print_file_copy_stats).is_ok() { + if let Ok(allows_links) = copy_files(&session_dir, &source_directory, + print_file_copy_stats) { debug!("successfully copied data from: {}", source_directory.display()); + if !allows_links { + tcx.sess.warn(&format!("Hard linking files in the incremental \ + compilation cache failed. Copying files \ + instead. Consider moving the cache \ + directory to a file system which supports \ + hard linking in session dir `{}`", + session_dir.display()) + ); + } + tcx.sess.init_incr_comp_session(session_dir, directory_lock); return Ok(true) } else { @@ -357,7 +368,7 @@ pub fn delete_all_session_dir_contents(sess: &Session) -> io::Result<()> { fn copy_files(target_dir: &Path, source_dir: &Path, print_stats_on_success: bool) - -> Result<(), ()> { + -> Result { // We acquire a shared lock on the lock file of the directory, so that // nobody deletes it out from under us while we are reading from it. let lock_file_path = lock_file_path(source_dir); @@ -409,7 +420,7 @@ fn copy_files(target_dir: &Path, println!("incr. comp. session directory: {} files copied", files_copied); } - Ok(()) + Ok(files_linked > 0 || files_copied == 0) } /// Generate unique directory path of the form: diff --git a/src/librustc_incremental/persist/hash.rs b/src/librustc_incremental/persist/hash.rs index ca173db15f..e365cbbd3a 100644 --- a/src/librustc_incremental/persist/hash.rs +++ b/src/librustc_incremental/persist/hash.rs @@ -18,6 +18,7 @@ use rustc_serialize::Decodable; use rustc_serialize::opaque::Decoder; use IncrementalHashesMap; +use ich::Fingerprint; use super::data::*; use super::fs::*; use super::file_format; @@ -25,7 +26,7 @@ use super::file_format; pub struct HashContext<'a, 'tcx: 'a> { pub tcx: TyCtxt<'a, 'tcx, 'tcx>, incremental_hashes_map: &'a IncrementalHashesMap, - item_metadata_hashes: FnvHashMap, + item_metadata_hashes: FnvHashMap, crate_hashes: FnvHashMap, } @@ -50,7 +51,7 @@ impl<'a, 'tcx> HashContext<'a, 'tcx> { } } - pub fn hash(&mut self, dep_node: &DepNode) -> Option { + pub fn hash(&mut self, dep_node: &DepNode) -> Option { match *dep_node { DepNode::Krate => { Some(self.incremental_hashes_map[dep_node]) @@ -89,7 +90,7 @@ impl<'a, 'tcx> HashContext<'a, 'tcx> { } } - fn metadata_hash(&mut self, def_id: DefId) -> u64 { + fn metadata_hash(&mut self, def_id: DefId) -> Fingerprint { debug!("metadata_hash(def_id={:?})", def_id); assert!(!def_id.is_local()); @@ -102,14 +103,15 @@ impl<'a, 'tcx> HashContext<'a, 'tcx> { // check whether we did not find detailed metadata for this // krate; in that case, we just use the krate's overall hash - if let Some(&hash) = self.crate_hashes.get(&def_id.krate) { - debug!("metadata_hash: def_id={:?} crate_hash={:?}", def_id, hash); + if let Some(&svh) = self.crate_hashes.get(&def_id.krate) { + debug!("metadata_hash: def_id={:?} crate_hash={:?}", def_id, svh); // micro-"optimization": avoid a cache miss if we ask // for metadata from this particular def-id again. - self.item_metadata_hashes.insert(def_id, hash.as_u64()); + let fingerprint = svh_to_fingerprint(svh); + self.item_metadata_hashes.insert(def_id, fingerprint); - return hash.as_u64(); + return fingerprint; } // otherwise, load the data and repeat. @@ -206,3 +208,7 @@ impl<'a, 'tcx> HashContext<'a, 'tcx> { Ok(()) } } + +fn svh_to_fingerprint(svh: Svh) -> Fingerprint { + Fingerprint::from_smaller_hash(svh.as_u64()) +} diff --git a/src/librustc_incremental/persist/load.rs b/src/librustc_incremental/persist/load.rs index db8d3125e5..7cef246b6c 100644 --- a/src/librustc_incremental/persist/load.rs +++ b/src/librustc_incremental/persist/load.rs @@ -22,6 +22,7 @@ use std::fs; use std::path::{Path}; use IncrementalHashesMap; +use ich::Fingerprint; use super::data::*; use super::directory::*; use super::dirty_clean; @@ -31,8 +32,6 @@ use super::file_format; pub type DirtyNodes = FnvHashSet>; -type CleanEdges = Vec<(DepNode, DepNode)>; - /// If we are in incremental mode, and a previous dep-graph exists, /// then load up those nodes/edges that are still valid into the /// dep-graph for this session. (This is assumed to be running very @@ -315,7 +314,7 @@ fn delete_dirty_work_product(tcx: TyCtxt, fn load_prev_metadata_hashes(tcx: TyCtxt, retraced: &RetracedDefIdDirectory, - output: &mut FnvHashMap) { + output: &mut FnvHashMap) { if !tcx.sess.opts.debugging_opts.query_dep_graph { return } diff --git a/src/librustc_incremental/persist/preds.rs b/src/librustc_incremental/persist/preds.rs index af13484e42..fe1d627253 100644 --- a/src/librustc_incremental/persist/preds.rs +++ b/src/librustc_incremental/persist/preds.rs @@ -14,6 +14,7 @@ use rustc_data_structures::fnv::FnvHashMap; use rustc_data_structures::graph::{DepthFirstTraversal, INCOMING, NodeIndex}; use super::hash::*; +use ich::Fingerprint; /// A data-structure that makes it easy to enumerate the hashable /// predecessors of any given dep-node. @@ -26,7 +27,7 @@ pub struct Predecessors<'query> { // - Keys: some hashable node // - Values: the hash thereof - pub hashes: FnvHashMap<&'query DepNode, u64>, + pub hashes: FnvHashMap<&'query DepNode, Fingerprint>, } impl<'q> Predecessors<'q> { diff --git a/src/librustc_incremental/persist/save.rs b/src/librustc_incremental/persist/save.rs index bc542b71ac..bc156b0e89 100644 --- a/src/librustc_incremental/persist/save.rs +++ b/src/librustc_incremental/persist/save.rs @@ -16,13 +16,13 @@ use rustc::ty::TyCtxt; use rustc_data_structures::fnv::FnvHashMap; use rustc_serialize::Encodable as RustcEncodable; use rustc_serialize::opaque::Encoder; -use std::hash::{Hash, Hasher}; +use std::hash::Hash; use std::io::{self, Cursor, Write}; use std::fs::{self, File}; use std::path::PathBuf; -use std::collections::hash_map::DefaultHasher; use IncrementalHashesMap; +use ich::Fingerprint; use super::data::*; use super::directory::*; use super::hash::*; @@ -30,6 +30,7 @@ use super::preds::*; use super::fs::*; use super::dirty_clean; use super::file_format; +use calculate_svh::hasher::IchHasher; pub fn save_dep_graph<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, incremental_hashes_map: &IncrementalHashesMap, @@ -185,7 +186,7 @@ pub fn encode_metadata_hashes(tcx: TyCtxt, svh: Svh, preds: &Predecessors, builder: &mut DefIdDirectoryBuilder, - current_metadata_hashes: &mut FnvHashMap, + current_metadata_hashes: &mut FnvHashMap, encoder: &mut Encoder) -> io::Result<()> { // For each `MetaData(X)` node where `X` is local, accumulate a @@ -233,7 +234,7 @@ pub fn encode_metadata_hashes(tcx: TyCtxt, // is the det. hash of the def-path. This is convenient // because we can sort this to get a stable ordering across // compilations, even if the def-ids themselves have changed. - let mut hashes: Vec<(DepNode, u64)> = sources.iter() + let mut hashes: Vec<(DepNode, Fingerprint)> = sources.iter() .map(|dep_node| { let hash_dep_node = dep_node.map_def(|&def_id| Some(def_id_hash(def_id))).unwrap(); let hash = preds.hashes[dep_node]; @@ -242,7 +243,7 @@ pub fn encode_metadata_hashes(tcx: TyCtxt, .collect(); hashes.sort(); - let mut state = DefaultHasher::new(); + let mut state = IchHasher::new(); hashes.hash(&mut state); let hash = state.finish(); diff --git a/src/librustc_lint/bad_style.rs b/src/librustc_lint/bad_style.rs index 84d65308f9..fea3de5952 100644 --- a/src/librustc_lint/bad_style.rs +++ b/src/librustc_lint/bad_style.rs @@ -24,19 +24,21 @@ use rustc::hir::intravisit::FnKind; pub enum MethodLateContext { TraitDefaultImpl, TraitImpl, - PlainImpl + PlainImpl, } pub fn method_context(cx: &LateContext, id: ast::NodeId, span: Span) -> MethodLateContext { let def_id = cx.tcx.map.local_def_id(id); match cx.tcx.impl_or_trait_items.borrow().get(&def_id) { None => span_bug!(span, "missing method descriptor?!"), - Some(item) => match item.container() { - ty::TraitContainer(..) => MethodLateContext::TraitDefaultImpl, - ty::ImplContainer(cid) => { - match cx.tcx.impl_trait_ref(cid) { - Some(_) => MethodLateContext::TraitImpl, - None => MethodLateContext::PlainImpl + Some(item) => { + match item.container() { + ty::TraitContainer(..) => MethodLateContext::TraitDefaultImpl, + ty::ImplContainer(cid) => { + match cx.tcx.impl_trait_ref(cid) { + Some(_) => MethodLateContext::TraitImpl, + None => MethodLateContext::PlainImpl, + } } } } @@ -63,19 +65,20 @@ impl NonCamelCaseTypes { // start with a non-lowercase letter rather than non-uppercase // ones (some scripts don't have a concept of upper/lowercase) - !name.is_empty() && - !name.chars().next().unwrap().is_lowercase() && - !name.contains('_') + !name.is_empty() && !name.chars().next().unwrap().is_lowercase() && !name.contains('_') } fn to_camel_case(s: &str) -> String { - s.split('_').flat_map(|word| word.chars().enumerate().map(|(i, c)| - if i == 0 { - c.to_uppercase().collect::() - } else { - c.to_lowercase().collect() - } - )).collect::>().concat() + s.split('_') + .flat_map(|word| { + word.chars().enumerate().map(|(i, c)| if i == 0 { + c.to_uppercase().collect::() + } else { + c.to_lowercase().collect() + }) + }) + .collect::>() + .concat() } let s = name.as_str(); @@ -83,9 +86,14 @@ impl NonCamelCaseTypes { if !is_camel_case(name) { let c = to_camel_case(&s); let m = if c.is_empty() { - format!("{} `{}` should have a camel case name such as `CamelCase`", sort, s) + format!("{} `{}` should have a camel case name such as `CamelCase`", + sort, + s) } else { - format!("{} `{}` should have a camel case name such as `{}`", sort, s, c) + format!("{} `{}` should have a camel case name such as `{}`", + sort, + s, + c) }; cx.span_lint(NON_CAMEL_CASE_TYPES, span, &m[..]); } @@ -100,10 +108,14 @@ impl LintPass for NonCamelCaseTypes { impl LateLintPass for NonCamelCaseTypes { fn check_item(&mut self, cx: &LateContext, it: &hir::Item) { - let extern_repr_count = it.attrs.iter().filter(|attr| { - attr::find_repr_attrs(cx.tcx.sess.diagnostic(), attr).iter() - .any(|r| r == &attr::ReprExtern) - }).count(); + let extern_repr_count = it.attrs + .iter() + .filter(|attr| { + attr::find_repr_attrs(cx.tcx.sess.diagnostic(), attr) + .iter() + .any(|r| r == &attr::ReprExtern) + }) + .count(); let has_extern_repr = extern_repr_count > 0; if has_extern_repr { @@ -111,12 +123,10 @@ impl LateLintPass for NonCamelCaseTypes { } match it.node { - hir::ItemTy(..) | hir::ItemStruct(..) | hir::ItemUnion(..) => { - self.check_case(cx, "type", it.name, it.span) - } - hir::ItemTrait(..) => { - self.check_case(cx, "trait", it.name, it.span) - } + hir::ItemTy(..) | + hir::ItemStruct(..) | + hir::ItemUnion(..) => self.check_case(cx, "type", it.name, it.span), + hir::ItemTrait(..) => self.check_case(cx, "trait", it.name, it.span), hir::ItemEnum(ref enum_definition, _) => { if has_extern_repr { return; @@ -126,7 +136,7 @@ impl LateLintPass for NonCamelCaseTypes { self.check_case(cx, "variant", variant.node.name, variant.span); } } - _ => () + _ => (), } } @@ -165,9 +175,7 @@ impl NonSnakeCase { continue; } for ch in s.chars() { - if !buf.is_empty() && buf != "'" - && ch.is_uppercase() - && !last_upper { + if !buf.is_empty() && buf != "'" && ch.is_uppercase() && !last_upper { words.push(buf); buf = String::new(); } @@ -205,10 +213,11 @@ impl NonSnakeCase { let sc = NonSnakeCase::to_snake_case(name); let msg = if sc != name { format!("{} `{}` should have a snake case name such as `{}`", - sort, name, sc) + sort, + name, + sc) } else { - format!("{} `{}` should have a snake case name", - sort, name) + format!("{} `{}` should have a snake case name", sort, name) }; match span { Some(span) => cx.span_lint(NON_SNAKE_CASE, span, &msg), @@ -226,8 +235,10 @@ impl LintPass for NonSnakeCase { impl LateLintPass for NonSnakeCase { fn check_crate(&mut self, cx: &LateContext, cr: &hir::Crate) { - let attr_crate_name = cr.attrs.iter().find(|at| at.check_name("crate_name")) - .and_then(|at| at.value_str().map(|s| (at, s))); + let attr_crate_name = cr.attrs + .iter() + .find(|at| at.check_name("crate_name")) + .and_then(|at| at.value_str().map(|s| (at, s))); if let Some(ref name) = cx.tcx.sess.opts.crate_name { self.check_snake_case(cx, "crate", name, None); } else if let Some((attr, ref name)) = attr_crate_name { @@ -235,22 +246,28 @@ impl LateLintPass for NonSnakeCase { } } - fn check_fn(&mut self, cx: &LateContext, - fk: FnKind, _: &hir::FnDecl, - _: &hir::Block, span: Span, id: ast::NodeId) { + fn check_fn(&mut self, + cx: &LateContext, + fk: FnKind, + _: &hir::FnDecl, + _: &hir::Block, + span: Span, + id: ast::NodeId) { match fk { - FnKind::Method(name, ..) => match method_context(cx, id, span) { - MethodLateContext::PlainImpl => { - self.check_snake_case(cx, "method", &name.as_str(), Some(span)) - }, - MethodLateContext::TraitDefaultImpl => { - self.check_snake_case(cx, "trait method", &name.as_str(), Some(span)) - }, - _ => (), - }, + FnKind::Method(name, ..) => { + match method_context(cx, id, span) { + MethodLateContext::PlainImpl => { + self.check_snake_case(cx, "method", &name.as_str(), Some(span)) + } + MethodLateContext::TraitDefaultImpl => { + self.check_snake_case(cx, "trait method", &name.as_str(), Some(span)) + } + _ => (), + } + } FnKind::ItemFn(name, ..) => { self.check_snake_case(cx, "function", &name.as_str(), Some(span)) - }, + } FnKind::Closure(_) => (), } } @@ -263,13 +280,17 @@ impl LateLintPass for NonSnakeCase { fn check_trait_item(&mut self, cx: &LateContext, trait_item: &hir::TraitItem) { if let hir::MethodTraitItem(_, None) = trait_item.node { - self.check_snake_case(cx, "trait method", &trait_item.name.as_str(), + self.check_snake_case(cx, + "trait method", + &trait_item.name.as_str(), Some(trait_item.span)); } } fn check_lifetime_def(&mut self, cx: &LateContext, t: &hir::LifetimeDef) { - self.check_snake_case(cx, "lifetime", &t.lifetime.name.as_str(), + self.check_snake_case(cx, + "lifetime", + &t.lifetime.name.as_str(), Some(t.lifetime.span)); } @@ -282,8 +303,12 @@ impl LateLintPass for NonSnakeCase { } } - fn check_struct_def(&mut self, cx: &LateContext, s: &hir::VariantData, - _: ast::Name, _: &hir::Generics, _: ast::NodeId) { + fn check_struct_def(&mut self, + cx: &LateContext, + s: &hir::VariantData, + _: ast::Name, + _: &hir::Generics, + _: ast::NodeId) { for sf in s.fields() { self.check_snake_case(cx, "structure field", &sf.name.as_str(), Some(sf.span)); } @@ -306,13 +331,16 @@ impl NonUpperCaseGlobals { if s.chars().any(|c| c.is_lowercase()) { let uc = NonSnakeCase::to_snake_case(&s).to_uppercase(); if uc != &s[..] { - cx.span_lint(NON_UPPER_CASE_GLOBALS, span, - &format!("{} `{}` should have an upper case name such as `{}`", - sort, s, uc)); + cx.span_lint(NON_UPPER_CASE_GLOBALS, + span, + &format!("{} `{}` should have an upper case name such as `{}`", + sort, + s, + uc)); } else { - cx.span_lint(NON_UPPER_CASE_GLOBALS, span, - &format!("{} `{}` should have an upper case name", - sort, s)); + cx.span_lint(NON_UPPER_CASE_GLOBALS, + span, + &format!("{} `{}` should have an upper case name", sort, s)); } } } @@ -327,9 +355,8 @@ impl LintPass for NonUpperCaseGlobals { impl LateLintPass for NonUpperCaseGlobals { fn check_item(&mut self, cx: &LateContext, it: &hir::Item) { match it.node { - // only check static constants - hir::ItemStatic(_, hir::MutImmutable, _) => { - NonUpperCaseGlobals::check_upper_case(cx, "static constant", it.name, it.span); + hir::ItemStatic(..) => { + NonUpperCaseGlobals::check_upper_case(cx, "static variable", it.name, it.span); } hir::ItemConst(..) => { NonUpperCaseGlobals::check_upper_case(cx, "constant", it.name, it.span); @@ -341,8 +368,7 @@ impl LateLintPass for NonUpperCaseGlobals { fn check_trait_item(&mut self, cx: &LateContext, ti: &hir::TraitItem) { match ti.node { hir::ConstTraitItem(..) => { - NonUpperCaseGlobals::check_upper_case(cx, "associated constant", - ti.name, ti.span); + NonUpperCaseGlobals::check_upper_case(cx, "associated constant", ti.name, ti.span); } _ => {} } @@ -351,8 +377,7 @@ impl LateLintPass for NonUpperCaseGlobals { fn check_impl_item(&mut self, cx: &LateContext, ii: &hir::ImplItem) { match ii.node { hir::ImplItemKind::Const(..) => { - NonUpperCaseGlobals::check_upper_case(cx, "associated constant", - ii.name, ii.span); + NonUpperCaseGlobals::check_upper_case(cx, "associated constant", ii.name, ii.span); } _ => {} } @@ -363,8 +388,10 @@ impl LateLintPass for NonUpperCaseGlobals { if let PatKind::Path(None, ref path) = p.node { if !path.global && path.segments.len() == 1 && path.segments[0].parameters.is_empty() { if let Def::Const(..) = cx.tcx.expect_def(p.id) { - NonUpperCaseGlobals::check_upper_case(cx, "constant in pattern", - path.segments[0].name, path.span); + NonUpperCaseGlobals::check_upper_case(cx, + "constant in pattern", + path.segments[0].name, + path.span); } } } diff --git a/src/librustc_lint/builtin.rs b/src/librustc_lint/builtin.rs index b610a924a3..28dc71fd59 100644 --- a/src/librustc_lint/builtin.rs +++ b/src/librustc_lint/builtin.rs @@ -34,18 +34,18 @@ use middle::stability; use rustc::cfg; use rustc::ty::subst::Substs; use rustc::ty::{self, Ty, TyCtxt}; -use rustc::ty::adjustment; use rustc::traits::{self, Reveal}; use rustc::hir::map as hir_map; -use util::nodemap::{NodeSet}; +use util::nodemap::NodeSet; use lint::{Level, LateContext, LintContext, LintArray, Lint}; -use lint::{LintPass, LateLintPass}; +use lint::{LintPass, LateLintPass, EarlyLintPass, EarlyContext}; use std::collections::HashSet; -use syntax::{ast}; +use syntax::ast; use syntax::attr; -use syntax_pos::{Span}; +use syntax::feature_gate::{AttributeGate, AttributeType, Stability, deprecated_attributes}; +use syntax_pos::Span; use rustc::hir::{self, PatKind}; use rustc::hir::intravisit::FnKind; @@ -75,7 +75,8 @@ impl LateLintPass for WhileTrue { if let hir::ExprWhile(ref cond, ..) = e.node { if let hir::ExprLit(ref lit) = cond.node { if let ast::LitKind::Bool(true) = lit.node { - cx.span_lint(WHILE_TRUE, e.span, + cx.span_lint(WHILE_TRUE, + e.span, "denote infinite loops with loop { ... }"); } } @@ -93,8 +94,7 @@ declare_lint! { pub struct BoxPointers; impl BoxPointers { - fn check_heap_type<'a, 'tcx>(&self, cx: &LateContext<'a, 'tcx>, - span: Span, ty: Ty<'tcx>) { + fn check_heap_type<'a, 'tcx>(&self, cx: &LateContext<'a, 'tcx>, span: Span, ty: Ty<'tcx>) { for leaf_ty in ty.walk() { if let ty::TyBox(_) = leaf_ty.sty { let m = format!("type uses owned (Box type) pointers: {}", ty); @@ -117,10 +117,10 @@ impl LateLintPass for BoxPointers { hir::ItemTy(..) | hir::ItemEnum(..) | hir::ItemStruct(..) | - hir::ItemUnion(..) => - self.check_heap_type(cx, it.span, - cx.tcx.node_id_to_type(it.id)), - _ => () + hir::ItemUnion(..) => { + self.check_heap_type(cx, it.span, cx.tcx.tables().node_id_to_type(it.id)) + } + _ => (), } // If it's a struct, we also have to check the fields' types @@ -128,16 +128,17 @@ impl LateLintPass for BoxPointers { hir::ItemStruct(ref struct_def, _) | hir::ItemUnion(ref struct_def, _) => { for struct_field in struct_def.fields() { - self.check_heap_type(cx, struct_field.span, - cx.tcx.node_id_to_type(struct_field.id)); + self.check_heap_type(cx, + struct_field.span, + cx.tcx.tables().node_id_to_type(struct_field.id)); } } - _ => () + _ => (), } } fn check_expr(&mut self, cx: &LateContext, e: &hir::Expr) { - let ty = cx.tcx.node_id_to_type(e.id); + let ty = cx.tcx.tables().node_id_to_type(e.id); self.check_heap_type(cx, e.span, ty); } } @@ -166,9 +167,11 @@ impl LateLintPass for NonShorthandFieldPatterns { } if let PatKind::Binding(_, ident, None) = fieldpat.node.pat.node { if ident.node == fieldpat.node.name { - cx.span_lint(NON_SHORTHAND_FIELD_PATTERNS, fieldpat.span, + cx.span_lint(NON_SHORTHAND_FIELD_PATTERNS, + fieldpat.span, &format!("the `{}:` in this pattern is redundant and can \ - be removed", ident.node)) + be removed", + ident.node)) } } } @@ -203,27 +206,35 @@ impl LateLintPass for UnsafeCode { fn check_item(&mut self, cx: &LateContext, it: &hir::Item) { match it.node { - hir::ItemTrait(hir::Unsafety::Unsafe, ..) => - cx.span_lint(UNSAFE_CODE, it.span, "declaration of an `unsafe` trait"), + hir::ItemTrait(hir::Unsafety::Unsafe, ..) => { + cx.span_lint(UNSAFE_CODE, it.span, "declaration of an `unsafe` trait") + } - hir::ItemImpl(hir::Unsafety::Unsafe, ..) => - cx.span_lint(UNSAFE_CODE, it.span, "implementation of an `unsafe` trait"), + hir::ItemImpl(hir::Unsafety::Unsafe, ..) => { + cx.span_lint(UNSAFE_CODE, it.span, "implementation of an `unsafe` trait") + } _ => return, } } - fn check_fn(&mut self, cx: &LateContext, fk: FnKind, _: &hir::FnDecl, - _: &hir::Block, span: Span, _: ast::NodeId) { + fn check_fn(&mut self, + cx: &LateContext, + fk: FnKind, + _: &hir::FnDecl, + _: &hir::Block, + span: Span, + _: ast::NodeId) { match fk { - FnKind::ItemFn(_, _, hir::Unsafety::Unsafe, ..) => - cx.span_lint(UNSAFE_CODE, span, "declaration of an `unsafe` function"), + FnKind::ItemFn(_, _, hir::Unsafety::Unsafe, ..) => { + cx.span_lint(UNSAFE_CODE, span, "declaration of an `unsafe` function") + } FnKind::Method(_, sig, ..) => { if sig.unsafety == hir::Unsafety::Unsafe { cx.span_lint(UNSAFE_CODE, span, "implementation of an `unsafe` method") } - }, + } _ => (), } @@ -232,7 +243,8 @@ impl LateLintPass for UnsafeCode { fn check_trait_item(&mut self, cx: &LateContext, trait_item: &hir::TraitItem) { if let hir::MethodTraitItem(ref sig, None) = trait_item.node { if sig.unsafety == hir::Unsafety::Unsafe { - cx.span_lint(UNSAFE_CODE, trait_item.span, + cx.span_lint(UNSAFE_CODE, + trait_item.span, "declaration of an `unsafe` method") } } @@ -263,9 +275,9 @@ pub struct MissingDoc { impl MissingDoc { pub fn new() -> MissingDoc { MissingDoc { - struct_def_stack: vec!(), + struct_def_stack: vec![], in_variant: false, - doc_hidden_stack: vec!(false), + doc_hidden_stack: vec![false], private_traits: HashSet::new(), } } @@ -275,11 +287,11 @@ impl MissingDoc { } fn check_missing_docs_attrs(&self, - cx: &LateContext, - id: Option, - attrs: &[ast::Attribute], - sp: Span, - desc: &'static str) { + cx: &LateContext, + id: Option, + attrs: &[ast::Attribute], + sp: Span, + desc: &'static str) { // If we're building a test harness, then warning about // documentation is probably not really relevant right now. if cx.sess().opts.test { @@ -302,7 +314,8 @@ impl MissingDoc { let has_doc = attrs.iter().any(|a| a.is_value_str() && a.name() == "doc"); if !has_doc { - cx.span_lint(MISSING_DOCS, sp, + cx.span_lint(MISSING_DOCS, + sp, &format!("missing documentation for {}", desc)); } } @@ -316,8 +329,10 @@ impl LintPass for MissingDoc { impl LateLintPass for MissingDoc { fn enter_lint_attrs(&mut self, _: &LateContext, attrs: &[ast::Attribute]) { - let doc_hidden = self.doc_hidden() || attrs.iter().any(|attr| { - attr.check_name("doc") && match attr.meta_item_list() { + let doc_hidden = self.doc_hidden() || + attrs.iter().any(|attr| { + attr.check_name("doc") && + match attr.meta_item_list() { None => false, Some(l) => attr::list_contains_name(&l[..], "hidden"), } @@ -329,13 +344,21 @@ impl LateLintPass for MissingDoc { self.doc_hidden_stack.pop().expect("empty doc_hidden_stack"); } - fn check_struct_def(&mut self, _: &LateContext, _: &hir::VariantData, - _: ast::Name, _: &hir::Generics, item_id: ast::NodeId) { + fn check_struct_def(&mut self, + _: &LateContext, + _: &hir::VariantData, + _: ast::Name, + _: &hir::Generics, + item_id: ast::NodeId) { self.struct_def_stack.push(item_id); } - fn check_struct_def_post(&mut self, _: &LateContext, _: &hir::VariantData, - _: ast::Name, _: &hir::Generics, item_id: ast::NodeId) { + fn check_struct_def_post(&mut self, + _: &LateContext, + _: &hir::VariantData, + _: ast::Name, + _: &hir::Generics, + item_id: ast::NodeId) { let popped = self.struct_def_stack.pop().expect("empty struct_def_stack"); assert!(popped == item_id); } @@ -358,10 +381,10 @@ impl LateLintPass for MissingDoc { for itm in items { self.private_traits.insert(itm.id); } - return + return; } "a trait" - }, + } hir::ItemTy(..) => "a type alias", hir::ItemImpl(.., Some(ref trait_ref), _, ref impl_items) => { // If the trait is private, add the impl items to private_traits so they don't get @@ -369,26 +392,30 @@ impl LateLintPass for MissingDoc { let real_trait = cx.tcx.expect_def(trait_ref.ref_id).def_id(); if let Some(node_id) = cx.tcx.map.as_local_node_id(real_trait) { match cx.tcx.map.find(node_id) { - Some(hir_map::NodeItem(item)) => if item.vis == hir::Visibility::Inherited { - for itm in impl_items { - self.private_traits.insert(itm.id); + Some(hir_map::NodeItem(item)) => { + if item.vis == hir::Visibility::Inherited { + for itm in impl_items { + self.private_traits.insert(itm.id); + } } - }, - _ => { } + } + _ => {} } } - return - }, + return; + } hir::ItemConst(..) => "a constant", hir::ItemStatic(..) => "a static", - _ => return + _ => return, }; self.check_missing_docs_attrs(cx, Some(it.id), &it.attrs, it.span, desc); } fn check_trait_item(&mut self, cx: &LateContext, trait_item: &hir::TraitItem) { - if self.private_traits.contains(&trait_item.id) { return } + if self.private_traits.contains(&trait_item.id) { + return; + } let desc = match trait_item.node { hir::ConstTraitItem(..) => "an associated constant", @@ -396,9 +423,11 @@ impl LateLintPass for MissingDoc { hir::TypeTraitItem(..) => "an associated type", }; - self.check_missing_docs_attrs(cx, Some(trait_item.id), + self.check_missing_docs_attrs(cx, + Some(trait_item.id), &trait_item.attrs, - trait_item.span, desc); + trait_item.span, + desc); } fn check_impl_item(&mut self, cx: &LateContext, impl_item: &hir::ImplItem) { @@ -412,26 +441,34 @@ impl LateLintPass for MissingDoc { hir::ImplItemKind::Method(..) => "a method", hir::ImplItemKind::Type(_) => "an associated type", }; - self.check_missing_docs_attrs(cx, Some(impl_item.id), + self.check_missing_docs_attrs(cx, + Some(impl_item.id), &impl_item.attrs, - impl_item.span, desc); + impl_item.span, + desc); } fn check_struct_field(&mut self, cx: &LateContext, sf: &hir::StructField) { if !sf.is_positional() { if sf.vis == hir::Public || self.in_variant { - let cur_struct_def = *self.struct_def_stack.last() + let cur_struct_def = *self.struct_def_stack + .last() .expect("empty struct_def_stack"); - self.check_missing_docs_attrs(cx, Some(cur_struct_def), - &sf.attrs, sf.span, + self.check_missing_docs_attrs(cx, + Some(cur_struct_def), + &sf.attrs, + sf.span, "a struct field") } } } fn check_variant(&mut self, cx: &LateContext, v: &hir::Variant, _: &hir::Generics) { - self.check_missing_docs_attrs(cx, Some(v.node.data.id()), - &v.node.attrs, v.span, "a variant"); + self.check_missing_docs_attrs(cx, + Some(v.node.data.id()), + &v.node.attrs, + v.span, + "a variant"); assert!(!self.in_variant); self.in_variant = true; } @@ -468,25 +505,27 @@ impl LateLintPass for MissingCopyImplementations { return; } let def = cx.tcx.lookup_adt_def(cx.tcx.map.local_def_id(item.id)); - (def, cx.tcx.mk_adt(def, Substs::empty(cx.tcx))) + (def, cx.tcx.mk_adt(def, cx.tcx.intern_substs(&[]))) } hir::ItemUnion(_, ref ast_generics) => { if ast_generics.is_parameterized() { return; } let def = cx.tcx.lookup_adt_def(cx.tcx.map.local_def_id(item.id)); - (def, cx.tcx.mk_adt(def, Substs::empty(cx.tcx))) + (def, cx.tcx.mk_adt(def, cx.tcx.intern_substs(&[]))) } hir::ItemEnum(_, ref ast_generics) => { if ast_generics.is_parameterized() { return; } let def = cx.tcx.lookup_adt_def(cx.tcx.map.local_def_id(item.id)); - (def, cx.tcx.mk_adt(def, Substs::empty(cx.tcx))) + (def, cx.tcx.mk_adt(def, cx.tcx.intern_substs(&[]))) } _ => return, }; - if def.has_dtor() { return; } + if def.has_dtor() { + return; + } let parameter_environment = cx.tcx.empty_parameter_environment(); // FIXME (@jroesch) should probably inver this so that the parameter env still impls this // method @@ -514,9 +553,7 @@ pub struct MissingDebugImplementations { impl MissingDebugImplementations { pub fn new() -> MissingDebugImplementations { - MissingDebugImplementations { - impling_types: None, - } + MissingDebugImplementations { impling_types: None } } } @@ -533,7 +570,9 @@ impl LateLintPass for MissingDebugImplementations { } match item.node { - hir::ItemStruct(..) | hir::ItemUnion(..) | hir::ItemEnum(..) => {}, + hir::ItemStruct(..) | + hir::ItemUnion(..) | + hir::ItemEnum(..) => {} _ => return, } @@ -547,7 +586,7 @@ impl LateLintPass for MissingDebugImplementations { let mut impls = NodeSet(); debug_def.for_each_impl(cx.tcx, |d| { if let Some(n) = cx.tcx.map.as_local_node_id(d) { - if let Some(ty_def) = cx.tcx.node_id_to_type(n).ty_to_def_id() { + if let Some(ty_def) = cx.tcx.tables().node_id_to_type(n).ty_to_def_id() { if let Some(node_id) = cx.tcx.map.as_local_node_id(ty_def) { impls.insert(node_id); } @@ -585,12 +624,13 @@ pub struct Deprecated { impl Deprecated { pub fn new() -> Deprecated { - Deprecated { - current_item: ast::CRATE_NODE_ID, - } + Deprecated { current_item: ast::CRATE_NODE_ID } } - fn lint(&self, cx: &LateContext, _id: DefId, span: Span, + fn lint(&self, + cx: &LateContext, + _id: DefId, + span: Span, stability: &Option<&attr::Stability>, deprecation: &Option) { // Deprecated attributes apply in-crate and cross-crate. @@ -641,9 +681,10 @@ impl LintPass for Deprecated { impl LateLintPass for Deprecated { fn check_item(&mut self, cx: &LateContext, item: &hir::Item) { self.push_item(item.id); - stability::check_item(cx.tcx, item, false, - &mut |id, sp, stab, depr| - self.lint(cx, id, sp, &stab, &depr)); + stability::check_item(cx.tcx, + item, + false, + &mut |id, sp, stab, depr| self.lint(cx, id, sp, &stab, &depr)); } fn check_item_post(&mut self, cx: &LateContext, item: &hir::Item) { @@ -651,27 +692,30 @@ impl LateLintPass for Deprecated { } fn check_expr(&mut self, cx: &LateContext, e: &hir::Expr) { - stability::check_expr(cx.tcx, e, - &mut |id, sp, stab, depr| - self.lint(cx, id, sp, &stab, &depr)); + stability::check_expr(cx.tcx, + e, + &mut |id, sp, stab, depr| self.lint(cx, id, sp, &stab, &depr)); } fn check_path(&mut self, cx: &LateContext, path: &hir::Path, id: ast::NodeId) { - stability::check_path(cx.tcx, path, id, - &mut |id, sp, stab, depr| - self.lint(cx, id, sp, &stab, &depr)); + stability::check_path(cx.tcx, + path, + id, + &mut |id, sp, stab, depr| self.lint(cx, id, sp, &stab, &depr)); } fn check_path_list_item(&mut self, cx: &LateContext, item: &hir::PathListItem) { - stability::check_path_list_item(cx.tcx, item, - &mut |id, sp, stab, depr| - self.lint(cx, id, sp, &stab, &depr)); + stability::check_path_list_item(cx.tcx, + item, + &mut |id, sp, stab, depr| { + self.lint(cx, id, sp, &stab, &depr) + }); } fn check_pat(&mut self, cx: &LateContext, pat: &hir::Pat) { - stability::check_pat(cx.tcx, pat, - &mut |id, sp, stab, depr| - self.lint(cx, id, sp, &stab, &depr)); + stability::check_pat(cx.tcx, + pat, + &mut |id, sp, stab, depr| self.lint(cx, id, sp, &stab, &depr)); } fn check_impl_item(&mut self, _: &LateContext, item: &hir::ImplItem) { @@ -699,6 +743,54 @@ impl LateLintPass for Deprecated { } } +declare_lint! { + DEPRECATED_ATTR, + Warn, + "detects use of deprecated attributes" +} + +/// Checks for use of attributes which have been deprecated. +#[derive(Clone)] +pub struct DeprecatedAttr { + // This is not free to compute, so we want to keep it around, rather than + // compute it for every attribute. + depr_attrs: Vec<&'static (&'static str, AttributeType, AttributeGate)>, +} + +impl DeprecatedAttr { + pub fn new() -> DeprecatedAttr { + DeprecatedAttr { + depr_attrs: deprecated_attributes(), + } + } +} + +impl LintPass for DeprecatedAttr { + fn get_lints(&self) -> LintArray { + lint_array!(DEPRECATED_ATTR) + } +} + +impl EarlyLintPass for DeprecatedAttr { + fn check_attribute(&mut self, cx: &EarlyContext, attr: &ast::Attribute) { + let name = &*attr.name(); + for &&(n, _, ref g) in &self.depr_attrs { + if n == name { + if let &AttributeGate::Gated(Stability::Deprecated(link), + ref name, + ref reason, + _) = g { + cx.span_lint(DEPRECATED, + attr.span, + &format!("use of deprecated attribute `{}`: {}. See {}", + name, reason, link)); + } + return; + } + } + } +} + declare_lint! { pub UNCONDITIONAL_RECURSION, Warn, @@ -716,15 +808,20 @@ impl LintPass for UnconditionalRecursion { } impl LateLintPass for UnconditionalRecursion { - fn check_fn(&mut self, cx: &LateContext, fn_kind: FnKind, _: &hir::FnDecl, - blk: &hir::Block, sp: Span, id: ast::NodeId) { + fn check_fn(&mut self, + cx: &LateContext, + fn_kind: FnKind, + _: &hir::FnDecl, + blk: &hir::Block, + sp: Span, + id: ast::NodeId) { let method = match fn_kind { FnKind::ItemFn(..) => None, FnKind::Method(..) => { cx.tcx.impl_or_trait_item(cx.tcx.map.local_def_id(id)).as_opt_method() } // closures can't recur, so they don't matter. - FnKind::Closure(_) => return + FnKind::Closure(_) => return, }; // Walk through this function (say `f`) looking to see if @@ -779,10 +876,8 @@ impl LateLintPass for UnconditionalRecursion { // is this a recursive call? let self_recursive = if node_id != ast::DUMMY_NODE_ID { match method { - Some(ref method) => { - expr_refers_to_this_method(cx.tcx, method, node_id) - } - None => expr_refers_to_this_fn(cx.tcx, id, node_id) + Some(ref method) => expr_refers_to_this_method(cx.tcx, method, node_id), + None => expr_refers_to_this_fn(cx.tcx, id, node_id), } } else { false @@ -808,7 +903,8 @@ impl LateLintPass for UnconditionalRecursion { // no break */ }`) shouldn't be linted unless it actually // recurs. if !reached_exit_without_self_call && !self_call_spans.is_empty() { - let mut db = cx.struct_span_lint(UNCONDITIONAL_RECURSION, sp, + let mut db = cx.struct_span_lint(UNCONDITIONAL_RECURSION, + sp, "function cannot return without recurring"); // FIXME #19668: these could be span_lint_note's instead of this manual guard. @@ -829,25 +925,25 @@ impl LateLintPass for UnconditionalRecursion { // Functions for identifying if the given Expr NodeId `id` // represents a call to the function `fn_id`/method `method`. - fn expr_refers_to_this_fn(tcx: TyCtxt, - fn_id: ast::NodeId, - id: ast::NodeId) -> bool { + fn expr_refers_to_this_fn(tcx: TyCtxt, fn_id: ast::NodeId, id: ast::NodeId) -> bool { match tcx.map.get(id) { hir_map::NodeExpr(&hir::Expr { node: hir::ExprCall(ref callee, _), .. }) => { - tcx.expect_def_or_none(callee.id).map_or(false, |def| { - def.def_id() == tcx.map.local_def_id(fn_id) - }) + tcx.expect_def_or_none(callee.id) + .map_or(false, |def| def.def_id() == tcx.map.local_def_id(fn_id)) } - _ => false + _ => false, } } // Check if the expression `id` performs a call to `method`. fn expr_refers_to_this_method<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, method: &ty::Method, - id: ast::NodeId) -> bool { + id: ast::NodeId) + -> bool { + use rustc::ty::adjustment::*; + // Check for method calls and overloaded operators. - let opt_m = tcx.tables.borrow().method_map.get(&ty::MethodCall::expr(id)).cloned(); + let opt_m = tcx.tables().method_map.get(&ty::MethodCall::expr(id)).cloned(); if let Some(m) = opt_m { if method_call_refers_to_method(tcx, method, m.def_id, m.substs, id) { return true; @@ -855,13 +951,12 @@ impl LateLintPass for UnconditionalRecursion { } // Check for overloaded autoderef method calls. - let opt_adj = tcx.tables.borrow().adjustments.get(&id).cloned(); - if let Some(adjustment::AdjustDerefRef(adj)) = opt_adj { - for i in 0..adj.autoderefs { + let opt_adj = tcx.tables().adjustments.get(&id).cloned(); + if let Some(Adjustment { kind: Adjust::DerefRef { autoderefs, .. }, .. }) = opt_adj { + for i in 0..autoderefs { let method_call = ty::MethodCall::autoderef(id, i as u32); - if let Some(m) = tcx.tables.borrow().method_map - .get(&method_call) - .cloned() { + if let Some(m) = tcx.tables().method_map.get(&method_call) + .cloned() { if method_call_refers_to_method(tcx, method, m.def_id, m.substs, id) { return true; } @@ -876,14 +971,15 @@ impl LateLintPass for UnconditionalRecursion { // it doesn't necessarily have a definition. match tcx.expect_def_or_none(callee.id) { Some(Def::Method(def_id)) => { - let item_substs = tcx.node_id_item_substs(callee.id); + let substs = tcx.tables().node_id_item_substs(callee.id) + .unwrap_or_else(|| tcx.intern_substs(&[])); method_call_refers_to_method( - tcx, method, def_id, &item_substs.substs, id) + tcx, method, def_id, substs, id) } - _ => false + _ => false, } } - _ => false + _ => false, } } @@ -893,15 +989,14 @@ impl LateLintPass for UnconditionalRecursion { method: &ty::Method, callee_id: DefId, callee_substs: &Substs<'tcx>, - expr_id: ast::NodeId) -> bool { + expr_id: ast::NodeId) + -> bool { let callee_item = tcx.impl_or_trait_item(callee_id); match callee_item.container() { // This is an inherent method, so the `def_id` refers // directly to the method definition. - ty::ImplContainer(_) => { - callee_id == method.def_id - } + ty::ImplContainer(_) => callee_id == method.def_id, // A trait method, from any number of possible sources. // Attempt to select a concrete impl before checking. @@ -939,13 +1034,12 @@ impl LateLintPass for UnconditionalRecursion { let container = ty::ImplContainer(vtable_impl.impl_def_id); // It matches if it comes from the same impl, // and has the same method name. - container == method.container - && callee_item.name() == method.name + container == method.container && callee_item.name() == method.name } // There's no way to know if this call is // recursive, so we assume it's not. - _ => false + _ => false, } }) } @@ -992,7 +1086,8 @@ impl LateLintPass for PluginAsLibrary { }; if prfn.is_some() { - cx.span_lint(PLUGIN_AS_LIBRARY, it.span, + cx.span_lint(PLUGIN_AS_LIBRARY, + it.span, "compiler plugin used as an ordinary library"); } } @@ -1050,15 +1145,15 @@ impl LateLintPass for InvalidNoMangleItems { "generic functions must be mangled"); } } - }, + } hir::ItemStatic(..) => { if attr::contains_name(&it.attrs, "no_mangle") && - !cx.access_levels.is_reachable(it.id) { + !cx.access_levels.is_reachable(it.id) { let msg = format!("static {} is marked #[no_mangle], but not exported", it.name); cx.span_lint(PRIVATE_NO_MANGLE_STATICS, it.span, &msg); } - }, + } hir::ItemConst(..) => { if attr::contains_name(&it.attrs, "no_mangle") { // Const items do not refer to a particular location in memory, and therefore @@ -1068,7 +1163,7 @@ impl LateLintPass for InvalidNoMangleItems { cx.span_lint(NO_MANGLE_CONST_ITEMS, it.span, msg); } } - _ => {}, + _ => {} } } } @@ -1092,36 +1187,38 @@ impl LateLintPass for MutableTransmutes { fn check_expr(&mut self, cx: &LateContext, expr: &hir::Expr) { use syntax::abi::Abi::RustIntrinsic; - let msg = "mutating transmuted &mut T from &T may cause undefined behavior,\ + let msg = "mutating transmuted &mut T from &T may cause undefined behavior, \ consider instead using an UnsafeCell"; match get_transmute_from_to(cx, expr) { Some((&ty::TyRef(_, from_mt), &ty::TyRef(_, to_mt))) => { - if to_mt.mutbl == hir::Mutability::MutMutable - && from_mt.mutbl == hir::Mutability::MutImmutable { + if to_mt.mutbl == hir::Mutability::MutMutable && + from_mt.mutbl == hir::Mutability::MutImmutable { cx.span_lint(MUTABLE_TRANSMUTES, expr.span, msg); } } - _ => () + _ => (), } - fn get_transmute_from_to<'a, 'tcx>(cx: &LateContext<'a, 'tcx>, expr: &hir::Expr) - -> Option<(&'tcx ty::TypeVariants<'tcx>, &'tcx ty::TypeVariants<'tcx>)> { + fn get_transmute_from_to<'a, 'tcx> + (cx: &LateContext<'a, 'tcx>, + expr: &hir::Expr) + -> Option<(&'tcx ty::TypeVariants<'tcx>, &'tcx ty::TypeVariants<'tcx>)> { match expr.node { hir::ExprPath(..) => (), - _ => return None + _ => return None, } if let Def::Fn(did) = cx.tcx.expect_def(expr.id) { if !def_id_is_transmute(cx, did) { return None; } - let typ = cx.tcx.node_id_to_type(expr.id); + let typ = cx.tcx.tables().node_id_to_type(expr.id); match typ.sty { ty::TyFnDef(.., ref bare_fn) if bare_fn.abi == RustIntrinsic => { let from = bare_fn.sig.0.inputs[0]; let to = bare_fn.sig.0.output; return Some((&from.sty, &to.sty)); - }, - _ => () + } + _ => (), } } None @@ -1130,7 +1227,7 @@ impl LateLintPass for MutableTransmutes { fn def_id_is_transmute(cx: &LateContext, def_id: DefId) -> bool { match cx.tcx.lookup_item_type(def_id).ty.sty { ty::TyFnDef(.., ref bfty) if bfty.abi == RustIntrinsic => (), - _ => return false + _ => return false, } cx.tcx.item_name(def_id).as_str() == "transmute" } @@ -1185,7 +1282,7 @@ impl LateLintPass for UnionsWithDropFields { if let hir::ItemUnion(ref vdata, _) = item.node { let param_env = &ty::ParameterEnvironment::for_item(ctx.tcx, item.id); for field in vdata.fields() { - let field_ty = ctx.tcx.node_id_to_type(field.id); + let field_ty = ctx.tcx.tables().node_id_to_type(field.id); if ctx.tcx.type_needs_drop_given_env(field_ty, param_env) { ctx.span_lint(UNIONS_WITH_DROP_FIELDS, field.span, diff --git a/src/librustc_lint/lib.rs b/src/librustc_lint/lib.rs index bc2979c806..114c0ea556 100644 --- a/src/librustc_lint/lib.rs +++ b/src/librustc_lint/lib.rs @@ -31,7 +31,7 @@ #![cfg_attr(test, feature(test))] #![feature(box_patterns)] #![feature(box_syntax)] -#![feature(dotdot_in_tuple_patterns)] +#![cfg_attr(stage0, feature(dotdot_in_tuple_patterns))] #![feature(quote)] #![feature(rustc_diagnostic_macros)] #![feature(rustc_private)] @@ -48,10 +48,10 @@ extern crate rustc_back; extern crate rustc_const_eval; extern crate syntax_pos; -pub use rustc::lint as lint; -pub use rustc::middle as middle; -pub use rustc::session as session; -pub use rustc::util as util; +pub use rustc::lint; +pub use rustc::middle; +pub use rustc::session; +pub use rustc::util; use session::Session; use lint::LintId; @@ -95,6 +95,14 @@ pub fn register_builtins(store: &mut lint::LintStore, sess: Option<&Session>) { ) } + macro_rules! add_early_builtin_with_new { + ($sess:ident, $($name:ident),*,) => ( + {$( + store.register_early_pass($sess, false, box $name::new()); + )*} + ) + } + macro_rules! add_lint_group { ($sess:ident, $name:expr, $($lint:ident),*) => ( store.register_group($sess, false, $name, vec![$(LintId::of($lint)),*]); @@ -105,6 +113,10 @@ pub fn register_builtins(store: &mut lint::LintStore, sess: Option<&Session>) { UnusedParens, ); + add_early_builtin_with_new!(sess, + DeprecatedAttr, + ); + add_builtin!(sess, HardwiredLints, WhileTrue, @@ -139,13 +151,24 @@ pub fn register_builtins(store: &mut lint::LintStore, sess: Option<&Session>) { MissingDebugImplementations, ); - add_lint_group!(sess, "bad_style", - NON_CAMEL_CASE_TYPES, NON_SNAKE_CASE, NON_UPPER_CASE_GLOBALS); - - add_lint_group!(sess, "unused", - UNUSED_IMPORTS, UNUSED_VARIABLES, UNUSED_ASSIGNMENTS, DEAD_CODE, - UNUSED_MUT, UNREACHABLE_CODE, UNUSED_MUST_USE, - UNUSED_UNSAFE, PATH_STATEMENTS, UNUSED_ATTRIBUTES); + add_lint_group!(sess, + "bad_style", + NON_CAMEL_CASE_TYPES, + NON_SNAKE_CASE, + NON_UPPER_CASE_GLOBALS); + + add_lint_group!(sess, + "unused", + UNUSED_IMPORTS, + UNUSED_VARIABLES, + UNUSED_ASSIGNMENTS, + DEAD_CODE, + UNUSED_MUT, + UNREACHABLE_CODE, + UNUSED_MUST_USE, + UNUSED_UNSAFE, + PATH_STATEMENTS, + UNUSED_ATTRIBUTES); // Guidelines for creating a future incompatibility lint: // @@ -155,27 +178,23 @@ pub fn register_builtins(store: &mut lint::LintStore, sess: Option<&Session>) { // and include the full URL. // - Later, change lint to error // - Eventually, remove lint - store.register_future_incompatible(sess, vec![ + store.register_future_incompatible(sess, + vec![ FutureIncompatibleInfo { id: LintId::of(PRIVATE_IN_PUBLIC), reference: "issue #34537 ", }, FutureIncompatibleInfo { id: LintId::of(INACCESSIBLE_EXTERN_CRATE), - reference: "PR 31362 ", + reference: "issue #36886 ", }, FutureIncompatibleInfo { id: LintId::of(INVALID_TYPE_PARAM_DEFAULT), - reference: "PR 30724 ", + reference: "issue #36887 ", }, FutureIncompatibleInfo { id: LintId::of(SUPER_OR_SELF_IN_GLOBAL_PATH), - reference: "PR #32403 ", - }, - FutureIncompatibleInfo { - id: LintId::of(MATCH_OF_UNIT_VARIANT_VIA_PAREN_DOTDOT), - reference: "RFC 218 ", + reference: "issue #36888 ", }, FutureIncompatibleInfo { id: LintId::of(TRANSMUTE_FROM_FN_ITEM_TYPES), @@ -183,15 +202,15 @@ pub fn register_builtins(store: &mut lint::LintStore, sess: Option<&Session>) { }, FutureIncompatibleInfo { id: LintId::of(OVERLAPPING_INHERENT_IMPLS), - reference: "issue #22889 ", + reference: "issue #36889 ", }, FutureIncompatibleInfo { id: LintId::of(ILLEGAL_FLOATING_POINT_CONSTANT_PATTERN), - reference: "RFC 1445 ", + reference: "issue #36890 ", }, FutureIncompatibleInfo { id: LintId::of(ILLEGAL_STRUCT_OR_ENUM_CONSTANT_PATTERN), - reference: "RFC 1445 ", + reference: "issue #36891 ", }, FutureIncompatibleInfo { id: LintId::of(HR_LIFETIME_IN_ASSOC_TYPE), @@ -199,21 +218,31 @@ pub fn register_builtins(store: &mut lint::LintStore, sess: Option<&Session>) { }, FutureIncompatibleInfo { id: LintId::of(LIFETIME_UNDERSCORE), - reference: "RFC 1177 ", + reference: "issue #36892 ", }, FutureIncompatibleInfo { id: LintId::of(SAFE_EXTERN_STATICS), - reference: "issue 36247 ", + reference: "issue #36247 ", + }, + FutureIncompatibleInfo { + id: LintId::of(PATTERNS_IN_FNS_WITHOUT_BODY), + reference: "issue #35203 ", + }, + FutureIncompatibleInfo { + id: LintId::of(EXTRA_REQUIREMENT_IN_IMPL), + reference: "issue #37166 ", }, ]); // Register renamed and removed lints store.register_renamed("unknown_features", "unused_features"); - store.register_removed("unsigned_negation", "replaced by negate_unsigned feature gate"); + store.register_removed("unsigned_negation", + "replaced by negate_unsigned feature gate"); store.register_removed("negate_unsigned", "cast a signed value instead"); store.register_removed("raw_pointer_derive", "using derive with raw pointers is ok"); // This was renamed to raw_pointer_derive, which was then removed, // so it is also considered removed - store.register_removed("raw_pointer_deriving", "using derive with raw pointers is ok"); + store.register_removed("raw_pointer_deriving", + "using derive with raw pointers is ok"); store.register_removed("drop_with_repr_extern", "drop flags have been removed"); } diff --git a/src/librustc_lint/types.rs b/src/librustc_lint/types.rs index 1209ced8dd..b04759955a 100644 --- a/src/librustc_lint/types.rs +++ b/src/librustc_lint/types.rs @@ -18,7 +18,7 @@ use rustc::traits::Reveal; use middle::const_val::ConstVal; use rustc_const_eval::eval_const_expr_partial; use rustc_const_eval::EvalHint::ExprTypeChecked; -use util::nodemap::{FnvHashSet}; +use util::nodemap::FnvHashSet; use lint::{LateContext, LintContext, LintArray}; use lint::{LintPass, LateLintPass}; @@ -91,15 +91,15 @@ pub struct TypeLimits { impl TypeLimits { pub fn new() -> TypeLimits { - TypeLimits { - negated_expr_id: ast::DUMMY_NODE_ID, - } + TypeLimits { negated_expr_id: ast::DUMMY_NODE_ID } } } impl LintPass for TypeLimits { fn get_lints(&self) -> LintArray { - lint_array!(UNUSED_COMPARISONS, OVERFLOWING_LITERALS, EXCEEDING_BITSHIFTS) + lint_array!(UNUSED_COMPARISONS, + OVERFLOWING_LITERALS, + EXCEEDING_BITSHIFTS) } } @@ -111,16 +111,16 @@ impl LateLintPass for TypeLimits { match lit.node { ast::LitKind::Int(_, ast::LitIntType::Unsigned(_)) => { forbid_unsigned_negation(cx, e.span); - }, + } ast::LitKind::Int(_, ast::LitIntType::Unsuffixed) => { - if let ty::TyUint(_) = cx.tcx.node_id_to_type(e.id).sty { + if let ty::TyUint(_) = cx.tcx.tables().node_id_to_type(e.id).sty { forbid_unsigned_negation(cx, e.span); } - }, - _ => () + } + _ => (), } } else { - let t = cx.tcx.node_id_to_type(expr.id); + let t = cx.tcx.tables().node_id_to_type(expr.id); if let ty::TyUint(_) = t.sty { forbid_unsigned_negation(cx, e.span); } @@ -129,43 +129,49 @@ impl LateLintPass for TypeLimits { if self.negated_expr_id != e.id { self.negated_expr_id = expr.id; } - }, + } hir::ExprBinary(binop, ref l, ref r) => { if is_comparison(binop) && !check_limits(cx.tcx, binop, &l, &r) { - cx.span_lint(UNUSED_COMPARISONS, e.span, + cx.span_lint(UNUSED_COMPARISONS, + e.span, "comparison is useless due to type limits"); } if binop.node.is_shift() { - let opt_ty_bits = match cx.tcx.node_id_to_type(l.id).sty { + let opt_ty_bits = match cx.tcx.tables().node_id_to_type(l.id).sty { ty::TyInt(t) => Some(int_ty_bits(t, cx.sess().target.int_type)), ty::TyUint(t) => Some(uint_ty_bits(t, cx.sess().target.uint_type)), - _ => None + _ => None, }; if let Some(bits) = opt_ty_bits { let exceeding = if let hir::ExprLit(ref lit) = r.node { - if let ast::LitKind::Int(shift, _) = lit.node { shift >= bits } - else { false } + if let ast::LitKind::Int(shift, _) = lit.node { + shift >= bits + } else { + false + } } else { match eval_const_expr_partial(cx.tcx, &r, ExprTypeChecked, None) { Ok(ConstVal::Integral(i)) => { - i.is_negative() || i.to_u64() - .map(|i| i >= bits) - .unwrap_or(true) - }, - _ => { false } + i.is_negative() || + i.to_u64() + .map(|i| i >= bits) + .unwrap_or(true) + } + _ => false, } }; if exceeding { - cx.span_lint(EXCEEDING_BITSHIFTS, e.span, + cx.span_lint(EXCEEDING_BITSHIFTS, + e.span, "bitshift exceeds the type's number of bits"); } }; } - }, + } hir::ExprLit(ref lit) => { - match cx.tcx.node_id_to_type(e.id).sty { + match cx.tcx.tables().node_id_to_type(e.id).sty { ty::TyInt(t) => { match lit.node { ast::LitKind::Int(v, ast::LitIntType::Signed(_)) | @@ -182,14 +188,15 @@ impl LateLintPass for TypeLimits { // avoiding use of -min to prevent overflow/panic if (negative && v > max as u64 + 1) || (!negative && v > max as u64) { - cx.span_lint(OVERFLOWING_LITERALS, e.span, + cx.span_lint(OVERFLOWING_LITERALS, + e.span, &format!("literal out of range for {:?}", t)); return; } } - _ => bug!() + _ => bug!(), }; - }, + } ty::TyUint(t) => { let uint_type = if let ast::UintTy::Us = t { cx.sess().target.uint_type @@ -201,13 +208,14 @@ impl LateLintPass for TypeLimits { // _v is u8, within range by definition ast::LitKind::Byte(_v) => return, ast::LitKind::Int(v, _) => v, - _ => bug!() + _ => bug!(), }; if lit_val < min || lit_val > max { - cx.span_lint(OVERFLOWING_LITERALS, e.span, + cx.span_lint(OVERFLOWING_LITERALS, + e.span, &format!("literal out of range for {:?}", t)); } - }, + } ty::TyFloat(t) => { let (min, max) = float_ty_range(t); let lit_val: f64 = match lit.node { @@ -215,70 +223,71 @@ impl LateLintPass for TypeLimits { ast::LitKind::FloatUnsuffixed(ref v) => { match v.parse() { Ok(f) => f, - Err(_) => return + Err(_) => return, } } - _ => bug!() + _ => bug!(), }; if lit_val < min || lit_val > max { - cx.span_lint(OVERFLOWING_LITERALS, e.span, + cx.span_lint(OVERFLOWING_LITERALS, + e.span, &format!("literal out of range for {:?}", t)); } - }, - _ => () + } + _ => (), }; - }, - _ => () + } + _ => (), }; - fn is_valid(binop: hir::BinOp, v: T, - min: T, max: T) -> bool { + fn is_valid(binop: hir::BinOp, v: T, min: T, max: T) -> bool { match binop.node { - hir::BiLt => v > min && v <= max, - hir::BiLe => v >= min && v < max, - hir::BiGt => v >= min && v < max, - hir::BiGe => v > min && v <= max, + hir::BiLt => v > min && v <= max, + hir::BiLe => v >= min && v < max, + hir::BiGt => v >= min && v < max, + hir::BiGe => v > min && v <= max, hir::BiEq | hir::BiNe => v >= min && v <= max, - _ => bug!() + _ => bug!(), } } fn rev_binop(binop: hir::BinOp) -> hir::BinOp { - codemap::respan(binop.span, match binop.node { - hir::BiLt => hir::BiGt, - hir::BiLe => hir::BiGe, - hir::BiGt => hir::BiLt, - hir::BiGe => hir::BiLe, - _ => return binop - }) + codemap::respan(binop.span, + match binop.node { + hir::BiLt => hir::BiGt, + hir::BiLe => hir::BiGe, + hir::BiGt => hir::BiLt, + hir::BiGe => hir::BiLe, + _ => return binop, + }) } // for isize & usize, be conservative with the warnings, so that the // warnings are consistent between 32- and 64-bit platforms fn int_ty_range(int_ty: ast::IntTy) -> (i64, i64) { match int_ty { - ast::IntTy::Is => (i64::MIN, i64::MAX), - ast::IntTy::I8 => (i8::MIN as i64, i8::MAX as i64), - ast::IntTy::I16 => (i16::MIN as i64, i16::MAX as i64), - ast::IntTy::I32 => (i32::MIN as i64, i32::MAX as i64), - ast::IntTy::I64 => (i64::MIN, i64::MAX) + ast::IntTy::Is => (i64::MIN, i64::MAX), + ast::IntTy::I8 => (i8::MIN as i64, i8::MAX as i64), + ast::IntTy::I16 => (i16::MIN as i64, i16::MAX as i64), + ast::IntTy::I32 => (i32::MIN as i64, i32::MAX as i64), + ast::IntTy::I64 => (i64::MIN, i64::MAX), } } fn uint_ty_range(uint_ty: ast::UintTy) -> (u64, u64) { match uint_ty { - ast::UintTy::Us => (u64::MIN, u64::MAX), - ast::UintTy::U8 => (u8::MIN as u64, u8::MAX as u64), - ast::UintTy::U16 => (u16::MIN as u64, u16::MAX as u64), - ast::UintTy::U32 => (u32::MIN as u64, u32::MAX as u64), - ast::UintTy::U64 => (u64::MIN, u64::MAX) + ast::UintTy::Us => (u64::MIN, u64::MAX), + ast::UintTy::U8 => (u8::MIN as u64, u8::MAX as u64), + ast::UintTy::U16 => (u16::MIN as u64, u16::MAX as u64), + ast::UintTy::U32 => (u32::MIN as u64, u32::MAX as u64), + ast::UintTy::U64 => (u64::MIN, u64::MAX), } } fn float_ty_range(float_ty: ast::FloatTy) -> (f64, f64) { match float_ty { ast::FloatTy::F32 => (f32::MIN as f64, f32::MAX as f64), - ast::FloatTy::F64 => (f64::MIN, f64::MAX) + ast::FloatTy::F64 => (f64::MIN, f64::MAX), } } @@ -305,60 +314,60 @@ impl LateLintPass for TypeLimits { fn check_limits<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, binop: hir::BinOp, l: &hir::Expr, - r: &hir::Expr) -> bool { + r: &hir::Expr) + -> bool { let (lit, expr, swap) = match (&l.node, &r.node) { (&hir::ExprLit(_), _) => (l, r, true), (_, &hir::ExprLit(_)) => (r, l, false), - _ => return true + _ => return true, }; // Normalize the binop so that the literal is always on the RHS in // the comparison - let norm_binop = if swap { - rev_binop(binop) - } else { - binop - }; - match tcx.node_id_to_type(expr.id).sty { + let norm_binop = if swap { rev_binop(binop) } else { binop }; + match tcx.tables().node_id_to_type(expr.id).sty { ty::TyInt(int_ty) => { let (min, max) = int_ty_range(int_ty); let lit_val: i64 = match lit.node { - hir::ExprLit(ref li) => match li.node { - ast::LitKind::Int(v, ast::LitIntType::Signed(_)) | - ast::LitKind::Int(v, ast::LitIntType::Unsuffixed) => v as i64, - _ => return true - }, - _ => bug!() + hir::ExprLit(ref li) => { + match li.node { + ast::LitKind::Int(v, ast::LitIntType::Signed(_)) | + ast::LitKind::Int(v, ast::LitIntType::Unsuffixed) => v as i64, + _ => return true, + } + } + _ => bug!(), }; is_valid(norm_binop, lit_val, min, max) } ty::TyUint(uint_ty) => { let (min, max): (u64, u64) = uint_ty_range(uint_ty); let lit_val: u64 = match lit.node { - hir::ExprLit(ref li) => match li.node { - ast::LitKind::Int(v, _) => v, - _ => return true - }, - _ => bug!() + hir::ExprLit(ref li) => { + match li.node { + ast::LitKind::Int(v, _) => v, + _ => return true, + } + } + _ => bug!(), }; is_valid(norm_binop, lit_val, min, max) } - _ => true + _ => true, } } fn is_comparison(binop: hir::BinOp) -> bool { match binop.node { - hir::BiEq | hir::BiLt | hir::BiLe | - hir::BiNe | hir::BiGe | hir::BiGt => true, - _ => false + hir::BiEq | hir::BiLt | hir::BiLe | hir::BiNe | hir::BiGe | hir::BiGt => true, + _ => false, } } fn forbid_unsigned_negation(cx: &LateContext, span: Span) { cx.sess() - .struct_span_err_with_code(span, "unary negation of unsigned integer", "E0519") - .span_help(span, "use a cast or the `!` operator") - .emit(); + .struct_span_err_with_code(span, "unary negation of unsigned integer", "E0519") + .span_help(span, "use a cast or the `!` operator") + .emit(); } } } @@ -370,7 +379,7 @@ declare_lint! { } struct ImproperCTypesVisitor<'a, 'tcx: 'a> { - cx: &'a LateContext<'a, 'tcx> + cx: &'a LateContext<'a, 'tcx>, } enum FfiResult { @@ -403,9 +412,13 @@ fn is_repr_nullable_ptr<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, if def.variants[data_idx].fields.len() == 1 { match def.variants[data_idx].fields[0].ty(tcx, substs).sty { - ty::TyFnPtr(_) => { return true; } - ty::TyRef(..) => { return true; } - _ => { } + ty::TyFnPtr(_) => { + return true; + } + ty::TyRef(..) => { + return true; + } + _ => {} } } } @@ -415,10 +428,7 @@ fn is_repr_nullable_ptr<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, impl<'a, 'tcx> ImproperCTypesVisitor<'a, 'tcx> { /// Check if the given type is "ffi-safe" (has a stable, well-defined /// representation which can be exported to C code). - fn check_type_for_ffi(&self, - cache: &mut FnvHashSet>, - ty: Ty<'tcx>) - -> FfiResult { + fn check_type_for_ffi(&self, cache: &mut FnvHashSet>, ty: Ty<'tcx>) -> FfiResult { use self::FfiResult::*; let cx = self.cx.tcx; @@ -431,112 +441,118 @@ impl<'a, 'tcx> ImproperCTypesVisitor<'a, 'tcx> { } match ty.sty { - ty::TyAdt(def, substs) => match def.adt_kind() { - AdtKind::Struct => { - if !cx.lookup_repr_hints(def.did).contains(&attr::ReprExtern) { - return FfiUnsafe( - "found struct without foreign-function-safe \ - representation annotation in foreign module, \ - consider adding a #[repr(C)] attribute to \ - the type"); - } + ty::TyAdt(def, substs) => { + match def.adt_kind() { + AdtKind::Struct => { + if !cx.lookup_repr_hints(def.did).contains(&attr::ReprExtern) { + return FfiUnsafe("found struct without foreign-function-safe \ + representation annotation in foreign module, \ + consider adding a #[repr(C)] attribute to the type"); + } - // We can't completely trust repr(C) markings; make sure the - // fields are actually safe. - if def.struct_variant().fields.is_empty() { - return FfiUnsafe( - "found zero-size struct in foreign module, consider \ - adding a member to this struct"); - } + // We can't completely trust repr(C) markings; make sure the + // fields are actually safe. + if def.struct_variant().fields.is_empty() { + return FfiUnsafe("found zero-size struct in foreign module, consider \ + adding a member to this struct"); + } - for field in &def.struct_variant().fields { - let field_ty = cx.normalize_associated_type(&field.ty(cx, substs)); - let r = self.check_type_for_ffi(cache, field_ty); - match r { - FfiSafe => {} - FfiBadStruct(..) | FfiBadUnion(..) | FfiBadEnum(..) => { return r; } - FfiUnsafe(s) => { return FfiBadStruct(def.did, s); } + for field in &def.struct_variant().fields { + let field_ty = cx.normalize_associated_type(&field.ty(cx, substs)); + let r = self.check_type_for_ffi(cache, field_ty); + match r { + FfiSafe => {} + FfiBadStruct(..) | FfiBadUnion(..) | FfiBadEnum(..) => { + return r; + } + FfiUnsafe(s) => { + return FfiBadStruct(def.did, s); + } + } } + FfiSafe } - FfiSafe - } - AdtKind::Union => { - if !cx.lookup_repr_hints(def.did).contains(&attr::ReprExtern) { - return FfiUnsafe( - "found union without foreign-function-safe \ - representation annotation in foreign module, \ - consider adding a #[repr(C)] attribute to \ - the type"); - } + AdtKind::Union => { + if !cx.lookup_repr_hints(def.did).contains(&attr::ReprExtern) { + return FfiUnsafe("found union without foreign-function-safe \ + representation annotation in foreign module, \ + consider adding a #[repr(C)] attribute to the type"); + } - for field in &def.struct_variant().fields { - let field_ty = cx.normalize_associated_type(&field.ty(cx, substs)); - let r = self.check_type_for_ffi(cache, field_ty); - match r { - FfiSafe => {} - FfiBadStruct(..) | FfiBadUnion(..) | FfiBadEnum(..) => { return r; } - FfiUnsafe(s) => { return FfiBadUnion(def.did, s); } + for field in &def.struct_variant().fields { + let field_ty = cx.normalize_associated_type(&field.ty(cx, substs)); + let r = self.check_type_for_ffi(cache, field_ty); + match r { + FfiSafe => {} + FfiBadStruct(..) | FfiBadUnion(..) | FfiBadEnum(..) => { + return r; + } + FfiUnsafe(s) => { + return FfiBadUnion(def.did, s); + } + } } + FfiSafe } - FfiSafe - } - AdtKind::Enum => { - if def.variants.is_empty() { - // Empty enums are okay... although sort of useless. - return FfiSafe - } + AdtKind::Enum => { + if def.variants.is_empty() { + // Empty enums are okay... although sort of useless. + return FfiSafe; + } - // Check for a repr() attribute to specify the size of the - // discriminant. - let repr_hints = cx.lookup_repr_hints(def.did); - match &repr_hints[..] { - &[] => { - // Special-case types like `Option`. - if !is_repr_nullable_ptr(cx, def, substs) { - return FfiUnsafe( - "found enum without foreign-function-safe \ - representation annotation in foreign module, \ - consider adding a #[repr(...)] attribute to \ - the type") + // Check for a repr() attribute to specify the size of the + // discriminant. + let repr_hints = cx.lookup_repr_hints(def.did); + match &repr_hints[..] { + &[] => { + // Special-case types like `Option`. + if !is_repr_nullable_ptr(cx, def, substs) { + return FfiUnsafe("found enum without foreign-function-safe \ + representation annotation in foreign \ + module, consider adding a #[repr(...)] \ + attribute to the type"); + } } - } - &[ref hint] => { - if !hint.is_ffi_safe() { + &[ref hint] => { + if !hint.is_ffi_safe() { + // FIXME: This shouldn't be reachable: we should check + // this earlier. + return FfiUnsafe("enum has unexpected #[repr(...)] attribute"); + } + + // Enum with an explicitly sized discriminant; either + // a C-style enum or a discriminated union. + + // The layout of enum variants is implicitly repr(C). + // FIXME: Is that correct? + } + _ => { // FIXME: This shouldn't be reachable: we should check // this earlier. - return FfiUnsafe( - "enum has unexpected #[repr(...)] attribute") + return FfiUnsafe("enum has too many #[repr(...)] attributes"); } - - // Enum with an explicitly sized discriminant; either - // a C-style enum or a discriminated union. - - // The layout of enum variants is implicitly repr(C). - // FIXME: Is that correct? } - _ => { - // FIXME: This shouldn't be reachable: we should check - // this earlier. - return FfiUnsafe( - "enum has too many #[repr(...)] attributes"); - } - } - // Check the contained variants. - for variant in &def.variants { - for field in &variant.fields { - let arg = cx.normalize_associated_type(&field.ty(cx, substs)); - let r = self.check_type_for_ffi(cache, arg); - match r { - FfiSafe => {} - FfiBadStruct(..) | FfiBadUnion(..) | FfiBadEnum(..) => { return r; } - FfiUnsafe(s) => { return FfiBadEnum(def.did, s); } + // Check the contained variants. + for variant in &def.variants { + for field in &variant.fields { + let arg = cx.normalize_associated_type(&field.ty(cx, substs)); + let r = self.check_type_for_ffi(cache, arg); + match r { + FfiSafe => {} + FfiBadStruct(..) | FfiBadUnion(..) | FfiBadEnum(..) => { + return r; + } + FfiUnsafe(s) => { + return FfiBadEnum(def.did, s); + } + } } } + FfiSafe } - FfiSafe } - }, + } ty::TyChar => { FfiUnsafe("found Rust type `char` in foreign module, while \ @@ -544,8 +560,7 @@ impl<'a, 'tcx> ImproperCTypesVisitor<'a, 'tcx> { } // Primitive types with a stable representation. - ty::TyBool | ty::TyInt(..) | ty::TyUint(..) | - ty::TyFloat(..) | ty::TyNever => FfiSafe, + ty::TyBool | ty::TyInt(..) | ty::TyUint(..) | ty::TyFloat(..) | ty::TyNever => FfiSafe, ty::TyBox(..) => { FfiUnsafe("found Rust type Box<_> in foreign module, \ @@ -572,24 +587,17 @@ impl<'a, 'tcx> ImproperCTypesVisitor<'a, 'tcx> { consider using a struct instead") } - ty::TyRawPtr(ref m) | ty::TyRef(_, ref m) => { - self.check_type_for_ffi(cache, m.ty) - } + ty::TyRawPtr(ref m) | + ty::TyRef(_, ref m) => self.check_type_for_ffi(cache, m.ty), - ty::TyArray(ty, _) => { - self.check_type_for_ffi(cache, ty) - } + ty::TyArray(ty, _) => self.check_type_for_ffi(cache, ty), ty::TyFnPtr(bare_fn) => { match bare_fn.abi { - Abi::Rust | - Abi::RustIntrinsic | - Abi::PlatformIntrinsic | - Abi::RustCall => { - return FfiUnsafe( - "found function pointer with Rust calling \ - convention in foreign module; consider using an \ - `extern` function pointer") + Abi::Rust | Abi::RustIntrinsic | Abi::PlatformIntrinsic | Abi::RustCall => { + return FfiUnsafe("found function pointer with Rust calling convention in \ + foreign module; consider using an `extern` function \ + pointer") } _ => {} } @@ -599,24 +607,30 @@ impl<'a, 'tcx> ImproperCTypesVisitor<'a, 'tcx> { let r = self.check_type_for_ffi(cache, sig.output); match r { FfiSafe => {} - _ => { return r; } + _ => { + return r; + } } } for arg in sig.inputs { let r = self.check_type_for_ffi(cache, arg); match r { FfiSafe => {} - _ => { return r; } + _ => { + return r; + } } } FfiSafe } - ty::TyParam(..) | ty::TyInfer(..) | ty::TyError | - ty::TyClosure(..) | ty::TyProjection(..) | ty::TyAnon(..) | - ty::TyFnDef(..) => { - bug!("Unexpected type in foreign function") - } + ty::TyParam(..) | + ty::TyInfer(..) | + ty::TyError | + ty::TyClosure(..) | + ty::TyProjection(..) | + ty::TyAnon(..) | + ty::TyFnDef(..) => bug!("Unexpected type in foreign function"), } } @@ -633,23 +647,28 @@ impl<'a, 'tcx> ImproperCTypesVisitor<'a, 'tcx> { FfiResult::FfiBadStruct(_, s) => { // FIXME: This diagnostic is difficult to read, and doesn't // point at the relevant field. - self.cx.span_lint(IMPROPER_CTYPES, sp, - &format!("found non-foreign-function-safe member in \ - struct marked #[repr(C)]: {}", s)); + self.cx.span_lint(IMPROPER_CTYPES, + sp, + &format!("found non-foreign-function-safe member in struct \ + marked #[repr(C)]: {}", + s)); } FfiResult::FfiBadUnion(_, s) => { // FIXME: This diagnostic is difficult to read, and doesn't // point at the relevant field. - self.cx.span_lint(IMPROPER_CTYPES, sp, - &format!("found non-foreign-function-safe member in \ - union marked #[repr(C)]: {}", s)); + self.cx.span_lint(IMPROPER_CTYPES, + sp, + &format!("found non-foreign-function-safe member in union \ + marked #[repr(C)]: {}", + s)); } FfiResult::FfiBadEnum(_, s) => { // FIXME: This diagnostic is difficult to read, and doesn't // point at the relevant variant. - self.cx.span_lint(IMPROPER_CTYPES, sp, - &format!("found non-foreign-function-safe member in \ - enum: {}", s)); + self.cx.span_lint(IMPROPER_CTYPES, + sp, + &format!("found non-foreign-function-safe member in enum: {}", + s)); } } } @@ -719,13 +738,13 @@ impl LintPass for VariantSizeDifferences { impl LateLintPass for VariantSizeDifferences { fn check_item(&mut self, cx: &LateContext, it: &hir::Item) { if let hir::ItemEnum(ref enum_definition, ref gens) = it.node { - if gens.ty_params.is_empty() { // sizes only make sense for non-generic types - let t = cx.tcx.node_id_to_type(it.id); + if gens.ty_params.is_empty() { + // sizes only make sense for non-generic types + let t = cx.tcx.tables().node_id_to_type(it.id); let layout = cx.tcx.infer_ctxt(None, None, Reveal::All).enter(|infcx| { let ty = cx.tcx.erase_regions(&t); - ty.layout(&infcx).unwrap_or_else(|e| { - bug!("failed to get layout for `{}`: {}", t, e) - }) + ty.layout(&infcx) + .unwrap_or_else(|e| bug!("failed to get layout for `{}`: {}", t, e)) }); if let Layout::General { ref variants, ref size, discr, .. } = *layout { @@ -738,23 +757,21 @@ impl LateLintPass for VariantSizeDifferences { .zip(variants) .map(|(variant, variant_layout)| { // Subtract the size of the enum discriminant - let bytes = variant_layout.min_size().bytes() - .saturating_sub(discr_size); + let bytes = variant_layout.min_size + .bytes() + .saturating_sub(discr_size); debug!("- variant `{}` is {} bytes large", variant.node.name, bytes); bytes }) .enumerate() - .fold((0, 0, 0), - |(l, s, li), (idx, size)| - if size > l { - (size, l, idx) - } else if size > s { - (l, size, li) - } else { - (l, s, li) - } - ); + .fold((0, 0, 0), |(l, s, li), (idx, size)| if size > l { + (size, l, idx) + } else if size > s { + (l, size, li) + } else { + (l, s, li) + }); // we only warn if the largest variant is at least thrice as large as // the second-largest. @@ -762,7 +779,8 @@ impl LateLintPass for VariantSizeDifferences { cx.span_lint(VARIANT_SIZE_DIFFERENCES, enum_definition.variants[largest_index].span, &format!("enum variant is more than three times larger \ - ({} bytes) than the next largest", largest)); + ({} bytes) than the next largest", + largest)); } } } diff --git a/src/librustc_lint/unused.rs b/src/librustc_lint/unused.rs index d31f16df69..15430a5c9f 100644 --- a/src/librustc_lint/unused.rs +++ b/src/librustc_lint/unused.rs @@ -49,8 +49,12 @@ impl UnusedMut { if let hir::BindByValue(hir::MutMutable) = mode { if !name.as_str().starts_with("_") { match mutables.entry(name.0 as usize) { - Vacant(entry) => { entry.insert(vec![id]); }, - Occupied(mut entry) => { entry.get_mut().push(id); }, + Vacant(entry) => { + entry.insert(vec![id]); + } + Occupied(mut entry) => { + entry.get_mut().push(id); + } } } } @@ -60,7 +64,8 @@ impl UnusedMut { let used_mutables = cx.tcx.used_mut_nodes.borrow(); for (_, v) in &mutables { if !v.iter().any(|e| used_mutables.contains(e)) { - cx.span_lint(UNUSED_MUT, cx.tcx.map.span(v[0]), + cx.span_lint(UNUSED_MUT, + cx.tcx.map.span(v[0]), "variable does not need to be mutable"); } } @@ -90,9 +95,13 @@ impl LateLintPass for UnusedMut { } } - fn check_fn(&mut self, cx: &LateContext, - _: FnKind, decl: &hir::FnDecl, - _: &hir::Block, _: Span, _: ast::NodeId) { + fn check_fn(&mut self, + cx: &LateContext, + _: FnKind, + decl: &hir::FnDecl, + _: &hir::Block, + _: Span, + _: ast::NodeId) { for a in &decl.inputs { self.check_unused_mut_pat(cx, slice::ref_slice(&a.pat)); } @@ -124,14 +133,14 @@ impl LateLintPass for UnusedResults { fn check_stmt(&mut self, cx: &LateContext, s: &hir::Stmt) { let expr = match s.node { hir::StmtSemi(ref expr, _) => &**expr, - _ => return + _ => return, }; if let hir::ExprRet(..) = expr.node { return; } - let t = cx.tcx.expr_ty(&expr); + let t = cx.tcx.tables().expr_ty(&expr); let warned = match t.sty { ty::TyTuple(ref tys) if tys.is_empty() => return, ty::TyNever => return, @@ -184,8 +193,8 @@ impl LateLintPass for UnusedUnsafe { if let hir::ExprBlock(ref blk) = e.node { // Don't warn about generated blocks, that'll just pollute the output. if blk.rules == hir::UnsafeBlock(hir::UserProvided) && - !cx.tcx.used_unsafe.borrow().contains(&blk.id) { - cx.span_lint(UNUSED_UNSAFE, blk.span, "unnecessary `unsafe` block"); + !cx.tcx.used_unsafe.borrow().contains(&blk.id) { + cx.span_lint(UNUSED_UNSAFE, blk.span, "unnecessary `unsafe` block"); } } } @@ -210,8 +219,7 @@ impl LateLintPass for PathStatements { fn check_stmt(&mut self, cx: &LateContext, s: &hir::Stmt) { if let hir::StmtSemi(ref expr, _) = s.node { if let hir::ExprPath(..) = expr.node { - cx.span_lint(PATH_STATEMENTS, s.span, - "path statement with no effect"); + cx.span_lint(PATH_STATEMENTS, s.span, "path statement with no effect"); } } } @@ -242,8 +250,8 @@ impl LateLintPass for UnusedAttributes { AttributeType::Whitelisted if attr.check_name(name) => { debug!("{:?} is Whitelisted", name); break; - }, - _ => () + } + _ => (), } } @@ -259,24 +267,22 @@ impl LateLintPass for UnusedAttributes { debug!("Emitting warning for: {:?}", attr); cx.span_lint(UNUSED_ATTRIBUTES, attr.span, "unused attribute"); // Is it a builtin attribute that must be used at the crate level? - let known_crate = KNOWN_ATTRIBUTES.iter().find(|&&(name, ty, _)| { - attr.name() == name && - ty == AttributeType::CrateLevel - }).is_some(); + let known_crate = KNOWN_ATTRIBUTES.iter() + .find(|&&(name, ty, _)| attr.name() == name && ty == AttributeType::CrateLevel) + .is_some(); // Has a plugin registered this attribute as one which must be used at // the crate level? let plugin_crate = plugin_attributes.iter() - .find(|&&(ref x, t)| { - &*attr.name() == x && - AttributeType::CrateLevel == t - }).is_some(); - if known_crate || plugin_crate { + .find(|&&(ref x, t)| &*attr.name() == x && AttributeType::CrateLevel == t) + .is_some(); + if known_crate || plugin_crate { let msg = match attr.node.style { - ast::AttrStyle::Outer => "crate-level attribute should be an inner \ - attribute: add an exclamation mark: #![foo]", - ast::AttrStyle::Inner => "crate-level attribute should be in the \ - root module", + ast::AttrStyle::Outer => { + "crate-level attribute should be an inner attribute: add an exclamation \ + mark: #![foo]" + } + ast::AttrStyle::Inner => "crate-level attribute should be in the root module", }; cx.span_lint(UNUSED_ATTRIBUTES, attr.span, msg); } @@ -296,12 +302,16 @@ declare_lint! { pub struct UnusedParens; impl UnusedParens { - fn check_unused_parens_core(&self, cx: &EarlyContext, value: &ast::Expr, msg: &str, + fn check_unused_parens_core(&self, + cx: &EarlyContext, + value: &ast::Expr, + msg: &str, struct_lit_needs_parens: bool) { if let ast::ExprKind::Paren(ref inner) = value.node { let necessary = struct_lit_needs_parens && contains_exterior_struct_lit(&inner); if !necessary { - cx.span_lint(UNUSED_PARENS, value.span, + cx.span_lint(UNUSED_PARENS, + value.span, &format!("unnecessary parentheses around {}", msg)) } } @@ -319,8 +329,7 @@ impl UnusedParens { ast::ExprKind::AssignOp(_, ref lhs, ref rhs) | ast::ExprKind::Binary(_, ref lhs, ref rhs) => { // X { y: 1 } + X { y: 2 } - contains_exterior_struct_lit(&lhs) || - contains_exterior_struct_lit(&rhs) + contains_exterior_struct_lit(&lhs) || contains_exterior_struct_lit(&rhs) } ast::ExprKind::Unary(_, ref x) | ast::ExprKind::Cast(ref x, _) | @@ -337,7 +346,7 @@ impl UnusedParens { contains_exterior_struct_lit(&exprs[0]) } - _ => false + _ => false, } } } @@ -363,18 +372,20 @@ impl EarlyLintPass for UnusedParens { Assign(_, ref value) => (value, "assigned value", false), AssignOp(.., ref value) => (value, "assigned value", false), InPlace(_, ref value) => (value, "emplacement value", false), - _ => return + _ => return, }; self.check_unused_parens_core(cx, &value, msg, struct_lit_needs_parens); } fn check_stmt(&mut self, cx: &EarlyContext, s: &ast::Stmt) { let (value, msg) = match s.node { - ast::StmtKind::Local(ref local) => match local.init { - Some(ref value) => (value, "assigned value"), - None => return - }, - _ => return + ast::StmtKind::Local(ref local) => { + match local.init { + Some(ref value) => (value, "assigned value"), + None => return, + } + } + _ => return, }; self.check_unused_parens_core(cx, &value, msg, false); } @@ -427,23 +438,23 @@ impl LateLintPass for UnusedAllocation { fn check_expr(&mut self, cx: &LateContext, e: &hir::Expr) { match e.node { hir::ExprBox(_) => {} - _ => return + _ => return, } - if let Some(adjustment) = cx.tcx.tables.borrow().adjustments.get(&e.id) { - if let adjustment::AdjustDerefRef(adjustment::AutoDerefRef { - ref autoref, .. - }) = *adjustment { + if let Some(adjustment) = cx.tcx.tables().adjustments.get(&e.id) { + if let adjustment::Adjust::DerefRef { autoref, .. } = adjustment.kind { match autoref { - &Some(adjustment::AutoPtr(_, hir::MutImmutable)) => { - cx.span_lint(UNUSED_ALLOCATION, e.span, + Some(adjustment::AutoBorrow::Ref(_, hir::MutImmutable)) => { + cx.span_lint(UNUSED_ALLOCATION, + e.span, "unnecessary allocation, use & instead"); } - &Some(adjustment::AutoPtr(_, hir::MutMutable)) => { - cx.span_lint(UNUSED_ALLOCATION, e.span, + Some(adjustment::AutoBorrow::Ref(_, hir::MutMutable)) => { + cx.span_lint(UNUSED_ALLOCATION, + e.span, "unnecessary allocation, use &mut instead"); } - _ => () + _ => (), } } } diff --git a/src/librustc_llvm/build.rs b/src/librustc_llvm/build.rs index 3f551476e2..4d3a4d09dc 100644 --- a/src/librustc_llvm/build.rs +++ b/src/librustc_llvm/build.rs @@ -22,22 +22,21 @@ fn main() { let target = env::var("TARGET").expect("TARGET was not set"); let llvm_config = env::var_os("LLVM_CONFIG") - .map(PathBuf::from) - .unwrap_or_else(|| { - if let Some(dir) = env::var_os("CARGO_TARGET_DIR") - .map(PathBuf::from) { - let to_test = dir.parent() - .unwrap() - .parent() - .unwrap() - .join(&target) - .join("llvm/bin/llvm-config"); - if Command::new(&to_test).output().is_ok() { - return to_test; - } - } - PathBuf::from("llvm-config") - }); + .map(PathBuf::from) + .unwrap_or_else(|| { + if let Some(dir) = env::var_os("CARGO_TARGET_DIR").map(PathBuf::from) { + let to_test = dir.parent() + .unwrap() + .parent() + .unwrap() + .join(&target) + .join("llvm/bin/llvm-config"); + if Command::new(&to_test).output().is_ok() { + return to_test; + } + } + PathBuf::from("llvm-config") + }); println!("cargo:rerun-if-changed={}", llvm_config.display()); @@ -66,7 +65,8 @@ fn main() { let host = env::var("HOST").expect("HOST was not set"); let is_crossed = target != host; - let optional_components = ["x86", "arm", "aarch64", "mips", "powerpc", "pnacl", "systemz"]; + let optional_components = + ["x86", "arm", "aarch64", "mips", "powerpc", "pnacl", "systemz", "jsbackend"]; // FIXME: surely we don't need all these components, right? Stuff like mcjit // or interpreter the compiler itself never uses. @@ -128,6 +128,19 @@ fn main() { // of llvm-config, not the target that we're attempting to link. let mut cmd = Command::new(&llvm_config); cmd.arg("--libs"); + + // Force static linking with "--link-static" if available. + let mut version_cmd = Command::new(&llvm_config); + version_cmd.arg("--version"); + let version_output = output(&mut version_cmd); + let mut parts = version_output.split('.'); + if let (Some(major), Some(minor)) = (parts.next().and_then(|s| s.parse::().ok()), + parts.next().and_then(|s| s.parse::().ok())) { + if major > 3 || (major == 3 && minor >= 8) { + cmd.arg("--link-static"); + } + } + if !is_crossed { cmd.arg("--system-libs"); } @@ -148,7 +161,7 @@ fn main() { // that off lib.trim_right_matches(".lib") } else { - continue + continue; }; // Don't need or want this library, but LLVM's CMake build system @@ -157,7 +170,7 @@ fn main() { // library and it otherwise may just pull in extra dependencies on // libedit which we don't want if name == "LLVMLineEditor" { - continue + continue; } let kind = if name.starts_with("LLVM") { @@ -178,7 +191,7 @@ fn main() { cmd.arg("--ldflags"); for lib in output(&mut cmd).split_whitespace() { if lib.starts_with("-LIBPATH:") { - println!("cargo:rustc-link-search=native={}", &lib[9..]); + println!("cargo:rustc-link-search=native={}", &lib[9..]); } else if is_crossed { if lib.starts_with("-L") { println!("cargo:rustc-link-search=native={}", diff --git a/src/librustc_llvm/diagnostic.rs b/src/librustc_llvm/diagnostic.rs index 8520ae1df6..8767f03b3e 100644 --- a/src/librustc_llvm/diagnostic.rs +++ b/src/librustc_llvm/diagnostic.rs @@ -33,8 +33,7 @@ pub enum OptimizationDiagnosticKind { impl OptimizationDiagnosticKind { pub fn describe(self) -> &'static str { match self { - OptimizationRemark | - OptimizationRemarkOther => "remark", + OptimizationRemark | OptimizationRemarkOther => "remark", OptimizationMissed => "missed", OptimizationAnalysis => "analysis", OptimizationAnalysisFPCommute => "floating-point", @@ -130,18 +129,14 @@ impl Diagnostic { Optimization(OptimizationDiagnostic::unpack(OptimizationAnalysis, di)) } - Dk::OptimizationRemarkAnalysisFPCommute => { - Optimization(OptimizationDiagnostic::unpack( - OptimizationAnalysisFPCommute, di)) + Optimization(OptimizationDiagnostic::unpack(OptimizationAnalysisFPCommute, di)) } Dk::OptimizationRemarkAnalysisAliasing => { - Optimization(OptimizationDiagnostic::unpack( - OptimizationAnalysisAliasing, di)) + Optimization(OptimizationDiagnostic::unpack(OptimizationAnalysisAliasing, di)) } - Dk::OptimizationFailure => { Optimization(OptimizationDiagnostic::unpack(OptimizationFailure, di)) } diff --git a/src/librustc_llvm/ffi.rs b/src/librustc_llvm/ffi.rs index 50c68d5e75..78a9d67ed7 100644 --- a/src/librustc_llvm/ffi.rs +++ b/src/librustc_llvm/ffi.rs @@ -8,11 +8,10 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -use debuginfo::{DIBuilderRef, DIDescriptor, - DIFile, DILexicalBlock, DISubprogram, DIType, - DIBasicType, DIDerivedType, DICompositeType, DIScope, - DIVariable, DIGlobalVariable, DIArray, DISubrange, - DITemplateTypeParameter, DIEnumerator, DINameSpace}; +use debuginfo::{DIBuilderRef, DIDescriptor, DIFile, DILexicalBlock, DISubprogram, DIType, + DIBasicType, DIDerivedType, DICompositeType, DIScope, DIVariable, + DIGlobalVariable, DIArray, DISubrange, DITemplateTypeParameter, DIEnumerator, + DINameSpace}; use libc::{c_uint, c_int, size_t, c_char}; use libc::{c_longlong, c_ulonglong, c_void}; @@ -44,7 +43,7 @@ pub enum CallConv { X86FastcallCallConv = 65, X86_64_SysV = 78, X86_64_Win64 = 79, - X86_VectorCall = 80 + X86_VectorCall = 80, } /// LLVMRustLinkage @@ -78,9 +77,9 @@ pub enum DiagnosticSeverity { #[derive(Copy, Clone)] #[repr(C)] pub enum DLLStorageClass { - Default = 0, - DllImport = 1, /* Function to be imported from DLL. */ - DllExport = 2, /* Function to be accessible from DLL. */ + Default = 0, + DllImport = 1, // Function to be imported from DLL. + DllExport = 2, // Function to be accessible from DLL. } bitflags! { @@ -180,23 +179,23 @@ pub enum RealPredicate { #[derive(Copy, Clone, PartialEq, Debug)] #[repr(C)] pub enum TypeKind { - Void = 0, - Half = 1, - Float = 2, - Double = 3, - X86_FP80 = 4, - FP128 = 5, + Void = 0, + Half = 1, + Float = 2, + Double = 3, + X86_FP80 = 4, + FP128 = 5, PPC_FP128 = 6, - Label = 7, - Integer = 8, - Function = 9, - Struct = 10, - Array = 11, - Pointer = 12, - Vector = 13, - Metadata = 14, - X86_MMX = 15, - Token = 16, + Label = 7, + Integer = 8, + Function = 9, + Struct = 10, + Array = 11, + Pointer = 12, + Vector = 13, + Metadata = 14, + X86_MMX = 15, + Token = 16, } /// LLVMAtomicRmwBinOp @@ -204,14 +203,14 @@ pub enum TypeKind { #[repr(C)] pub enum AtomicRmwBinOp { AtomicXchg = 0, - AtomicAdd = 1, - AtomicSub = 2, - AtomicAnd = 3, + AtomicAdd = 1, + AtomicSub = 2, + AtomicAnd = 3, AtomicNand = 4, - AtomicOr = 5, - AtomicXor = 6, - AtomicMax = 7, - AtomicMin = 8, + AtomicOr = 5, + AtomicXor = 6, + AtomicMax = 7, + AtomicMin = 8, AtomicUMax = 9, AtomicUMin = 10, } @@ -227,7 +226,7 @@ pub enum AtomicOrdering { Acquire = 4, Release = 5, AcquireRelease = 6, - SequentiallyConsistent = 7 + SequentiallyConsistent = 7, } /// LLVMRustSynchronizationScope @@ -429,7 +428,7 @@ pub type InlineAsmDiagHandler = unsafe extern "C" fn(SMDiagnosticRef, *const c_v pub mod debuginfo { pub use self::DIDescriptorFlags::*; - use super::{MetadataRef}; + use super::MetadataRef; #[allow(missing_copy_implementations)] pub enum DIBuilder_opaque {} @@ -455,22 +454,22 @@ pub mod debuginfo { #[derive(Copy, Clone)] pub enum DIDescriptorFlags { - FlagPrivate = 1 << 0, - FlagProtected = 1 << 1, - FlagFwdDecl = 1 << 2, - FlagAppleBlock = 1 << 3, - FlagBlockByrefStruct = 1 << 4, - FlagVirtual = 1 << 5, - FlagArtificial = 1 << 6, - FlagExplicit = 1 << 7, - FlagPrototyped = 1 << 8, - FlagObjcClassComplete = 1 << 9, - FlagObjectPointer = 1 << 10, - FlagVector = 1 << 11, - FlagStaticMember = 1 << 12, - FlagIndirectVariable = 1 << 13, - FlagLValueReference = 1 << 14, - FlagRValueReference = 1 << 15 + FlagPrivate = 1 << 0, + FlagProtected = 1 << 1, + FlagFwdDecl = 1 << 2, + FlagAppleBlock = 1 << 3, + FlagBlockByrefStruct = 1 << 4, + FlagVirtual = 1 << 5, + FlagArtificial = 1 << 6, + FlagExplicit = 1 << 7, + FlagPrototyped = 1 << 8, + FlagObjcClassComplete = 1 << 9, + FlagObjectPointer = 1 << 10, + FlagVector = 1 << 11, + FlagStaticMember = 1 << 12, + FlagIndirectVariable = 1 << 13, + FlagLValueReference = 1 << 14, + FlagRValueReference = 1 << 15, } } @@ -487,22 +486,17 @@ pub mod debuginfo { // set of the libraries we need to link to LLVM for. #[link(name = "rustllvm", kind = "static")] #[cfg(not(cargobuild))] -extern {} +extern "C" {} #[linked_from = "rustllvm"] // not quite true but good enough -extern { - /* Create and destroy contexts. */ +extern "C" { + // Create and destroy contexts. pub fn LLVMContextCreate() -> ContextRef; pub fn LLVMContextDispose(C: ContextRef); - pub fn LLVMGetMDKindIDInContext(C: ContextRef, - Name: *const c_char, - SLen: c_uint) - -> c_uint; + pub fn LLVMGetMDKindIDInContext(C: ContextRef, Name: *const c_char, SLen: c_uint) -> c_uint; - /* Create and destroy modules. */ - pub fn LLVMModuleCreateWithNameInContext(ModuleID: *const c_char, - C: ContextRef) - -> ModuleRef; + // Create and destroy modules. + pub fn LLVMModuleCreateWithNameInContext(ModuleID: *const c_char, C: ContextRef) -> ModuleRef; pub fn LLVMGetModuleContext(M: ModuleRef) -> ContextRef; pub fn LLVMCloneModule(M: ModuleRef) -> ModuleRef; pub fn LLVMDisposeModule(M: ModuleRef); @@ -527,25 +521,24 @@ extern { /// See llvm::LLVMType::getContext. pub fn LLVMGetTypeContext(Ty: TypeRef) -> ContextRef; - /* Operations on integer types */ + // Operations on integer types pub fn LLVMInt1TypeInContext(C: ContextRef) -> TypeRef; pub fn LLVMInt8TypeInContext(C: ContextRef) -> TypeRef; pub fn LLVMInt16TypeInContext(C: ContextRef) -> TypeRef; pub fn LLVMInt32TypeInContext(C: ContextRef) -> TypeRef; pub fn LLVMInt64TypeInContext(C: ContextRef) -> TypeRef; - pub fn LLVMIntTypeInContext(C: ContextRef, NumBits: c_uint) - -> TypeRef; + pub fn LLVMIntTypeInContext(C: ContextRef, NumBits: c_uint) -> TypeRef; pub fn LLVMGetIntTypeWidth(IntegerTy: TypeRef) -> c_uint; - /* Operations on real types */ + // Operations on real types pub fn LLVMFloatTypeInContext(C: ContextRef) -> TypeRef; pub fn LLVMDoubleTypeInContext(C: ContextRef) -> TypeRef; pub fn LLVMX86FP80TypeInContext(C: ContextRef) -> TypeRef; pub fn LLVMFP128TypeInContext(C: ContextRef) -> TypeRef; pub fn LLVMPPCFP128TypeInContext(C: ContextRef) -> TypeRef; - /* Operations on function types */ + // Operations on function types pub fn LLVMFunctionType(ReturnType: TypeRef, ParamTypes: *const TypeRef, ParamCount: c_uint, @@ -556,37 +549,33 @@ extern { pub fn LLVMCountParamTypes(FunctionTy: TypeRef) -> c_uint; pub fn LLVMGetParamTypes(FunctionTy: TypeRef, Dest: *mut TypeRef); - /* Operations on struct types */ + // Operations on struct types pub fn LLVMStructTypeInContext(C: ContextRef, ElementTypes: *const TypeRef, ElementCount: c_uint, Packed: Bool) -> TypeRef; pub fn LLVMCountStructElementTypes(StructTy: TypeRef) -> c_uint; - pub fn LLVMGetStructElementTypes(StructTy: TypeRef, - Dest: *mut TypeRef); + pub fn LLVMGetStructElementTypes(StructTy: TypeRef, Dest: *mut TypeRef); pub fn LLVMIsPackedStruct(StructTy: TypeRef) -> Bool; - /* Operations on array, pointer, and vector types (sequence types) */ + // Operations on array, pointer, and vector types (sequence types) pub fn LLVMRustArrayType(ElementType: TypeRef, ElementCount: u64) -> TypeRef; - pub fn LLVMPointerType(ElementType: TypeRef, AddressSpace: c_uint) - -> TypeRef; - pub fn LLVMVectorType(ElementType: TypeRef, ElementCount: c_uint) - -> TypeRef; + pub fn LLVMPointerType(ElementType: TypeRef, AddressSpace: c_uint) -> TypeRef; + pub fn LLVMVectorType(ElementType: TypeRef, ElementCount: c_uint) -> TypeRef; pub fn LLVMGetElementType(Ty: TypeRef) -> TypeRef; pub fn LLVMGetArrayLength(ArrayTy: TypeRef) -> c_uint; pub fn LLVMGetPointerAddressSpace(PointerTy: TypeRef) -> c_uint; - pub fn LLVMGetPointerToGlobal(EE: ExecutionEngineRef, V: ValueRef) - -> *const c_void; + pub fn LLVMGetPointerToGlobal(EE: ExecutionEngineRef, V: ValueRef) -> *const c_void; pub fn LLVMGetVectorSize(VectorTy: TypeRef) -> c_uint; - /* Operations on other types */ + // Operations on other types pub fn LLVMVoidTypeInContext(C: ContextRef) -> TypeRef; pub fn LLVMLabelTypeInContext(C: ContextRef) -> TypeRef; pub fn LLVMRustMetadataTypeInContext(C: ContextRef) -> TypeRef; - /* Operations on all values */ + // Operations on all values pub fn LLVMTypeOf(Val: ValueRef) -> TypeRef; pub fn LLVMGetValueName(Val: ValueRef) -> *const c_char; pub fn LLVMSetValueName(Val: ValueRef, Name: *const c_char); @@ -594,58 +583,45 @@ extern { pub fn LLVMReplaceAllUsesWith(OldVal: ValueRef, NewVal: ValueRef); pub fn LLVMSetMetadata(Val: ValueRef, KindID: c_uint, Node: ValueRef); - /* Operations on Uses */ + // Operations on Uses pub fn LLVMGetFirstUse(Val: ValueRef) -> UseRef; pub fn LLVMGetNextUse(U: UseRef) -> UseRef; pub fn LLVMGetUser(U: UseRef) -> ValueRef; pub fn LLVMGetUsedValue(U: UseRef) -> ValueRef; - /* Operations on Users */ + // Operations on Users pub fn LLVMGetNumOperands(Val: ValueRef) -> c_int; pub fn LLVMGetOperand(Val: ValueRef, Index: c_uint) -> ValueRef; pub fn LLVMSetOperand(Val: ValueRef, Index: c_uint, Op: ValueRef); - /* Operations on constants of any type */ + // Operations on constants of any type pub fn LLVMConstNull(Ty: TypeRef) -> ValueRef; - /* all zeroes */ + // all zeroes pub fn LLVMConstAllOnes(Ty: TypeRef) -> ValueRef; - pub fn LLVMConstICmp(Pred: IntPredicate, V1: ValueRef, V2: ValueRef) - -> ValueRef; - pub fn LLVMConstFCmp(Pred: RealPredicate, V1: ValueRef, V2: ValueRef) - -> ValueRef; - /* only for isize/vector */ + pub fn LLVMConstICmp(Pred: IntPredicate, V1: ValueRef, V2: ValueRef) -> ValueRef; + pub fn LLVMConstFCmp(Pred: RealPredicate, V1: ValueRef, V2: ValueRef) -> ValueRef; + // only for isize/vector pub fn LLVMGetUndef(Ty: TypeRef) -> ValueRef; pub fn LLVMIsConstant(Val: ValueRef) -> Bool; pub fn LLVMIsNull(Val: ValueRef) -> Bool; pub fn LLVMIsUndef(Val: ValueRef) -> Bool; pub fn LLVMConstPointerNull(Ty: TypeRef) -> ValueRef; - /* Operations on metadata */ - pub fn LLVMMDStringInContext(C: ContextRef, - Str: *const c_char, - SLen: c_uint) - -> ValueRef; - pub fn LLVMMDNodeInContext(C: ContextRef, - Vals: *const ValueRef, - Count: c_uint) - -> ValueRef; - pub fn LLVMAddNamedMetadataOperand(M: ModuleRef, - Str: *const c_char, - Val: ValueRef); + // Operations on metadata + pub fn LLVMMDStringInContext(C: ContextRef, Str: *const c_char, SLen: c_uint) -> ValueRef; + pub fn LLVMMDNodeInContext(C: ContextRef, Vals: *const ValueRef, Count: c_uint) -> ValueRef; + pub fn LLVMAddNamedMetadataOperand(M: ModuleRef, Str: *const c_char, Val: ValueRef); - /* Operations on scalar constants */ - pub fn LLVMConstInt(IntTy: TypeRef, N: c_ulonglong, SignExtend: Bool) - -> ValueRef; - pub fn LLVMConstIntOfString(IntTy: TypeRef, Text: *const c_char, Radix: u8) - -> ValueRef; + // Operations on scalar constants + pub fn LLVMConstInt(IntTy: TypeRef, N: c_ulonglong, SignExtend: Bool) -> ValueRef; + pub fn LLVMConstIntOfString(IntTy: TypeRef, Text: *const c_char, Radix: u8) -> ValueRef; pub fn LLVMConstIntOfStringAndSize(IntTy: TypeRef, Text: *const c_char, SLen: c_uint, Radix: u8) -> ValueRef; pub fn LLVMConstReal(RealTy: TypeRef, N: f64) -> ValueRef; - pub fn LLVMConstRealOfString(RealTy: TypeRef, Text: *const c_char) - -> ValueRef; + pub fn LLVMConstRealOfString(RealTy: TypeRef, Text: *const c_char) -> ValueRef; pub fn LLVMConstRealOfStringAndSize(RealTy: TypeRef, Text: *const c_char, SLen: c_uint) @@ -654,7 +630,7 @@ extern { pub fn LLVMConstIntGetSExtValue(ConstantVal: ValueRef) -> c_longlong; - /* Operations on composite constants */ + // Operations on composite constants pub fn LLVMConstStringInContext(C: ContextRef, Str: *const c_char, Length: c_uint, @@ -670,10 +646,9 @@ extern { ConstantVals: *const ValueRef, Length: c_uint) -> ValueRef; - pub fn LLVMConstVector(ScalarConstantVals: *const ValueRef, Size: c_uint) - -> ValueRef; + pub fn LLVMConstVector(ScalarConstantVals: *const ValueRef, Size: c_uint) -> ValueRef; - /* Constant expressions */ + // Constant expressions pub fn LLVMAlignOf(Ty: TypeRef) -> ValueRef; pub fn LLVMSizeOf(Ty: TypeRef) -> ValueRef; pub fn LLVMConstNeg(ConstantVal: ValueRef) -> ValueRef; @@ -681,57 +656,31 @@ extern { pub fn LLVMConstNUWNeg(ConstantVal: ValueRef) -> ValueRef; pub fn LLVMConstFNeg(ConstantVal: ValueRef) -> ValueRef; pub fn LLVMConstNot(ConstantVal: ValueRef) -> ValueRef; - pub fn LLVMConstAdd(LHSConstant: ValueRef, RHSConstant: ValueRef) - -> ValueRef; - pub fn LLVMConstNSWAdd(LHSConstant: ValueRef, RHSConstant: ValueRef) - -> ValueRef; - pub fn LLVMConstNUWAdd(LHSConstant: ValueRef, RHSConstant: ValueRef) - -> ValueRef; - pub fn LLVMConstFAdd(LHSConstant: ValueRef, RHSConstant: ValueRef) - -> ValueRef; - pub fn LLVMConstSub(LHSConstant: ValueRef, RHSConstant: ValueRef) - -> ValueRef; - pub fn LLVMConstNSWSub(LHSConstant: ValueRef, RHSConstant: ValueRef) - -> ValueRef; - pub fn LLVMConstNUWSub(LHSConstant: ValueRef, RHSConstant: ValueRef) - -> ValueRef; - pub fn LLVMConstFSub(LHSConstant: ValueRef, RHSConstant: ValueRef) - -> ValueRef; - pub fn LLVMConstMul(LHSConstant: ValueRef, RHSConstant: ValueRef) - -> ValueRef; - pub fn LLVMConstNSWMul(LHSConstant: ValueRef, RHSConstant: ValueRef) - -> ValueRef; - pub fn LLVMConstNUWMul(LHSConstant: ValueRef, RHSConstant: ValueRef) - -> ValueRef; - pub fn LLVMConstFMul(LHSConstant: ValueRef, RHSConstant: ValueRef) - -> ValueRef; - pub fn LLVMConstUDiv(LHSConstant: ValueRef, RHSConstant: ValueRef) - -> ValueRef; - pub fn LLVMConstSDiv(LHSConstant: ValueRef, RHSConstant: ValueRef) - -> ValueRef; - pub fn LLVMConstExactSDiv(LHSConstant: ValueRef, - RHSConstant: ValueRef) - -> ValueRef; - pub fn LLVMConstFDiv(LHSConstant: ValueRef, RHSConstant: ValueRef) - -> ValueRef; - pub fn LLVMConstURem(LHSConstant: ValueRef, RHSConstant: ValueRef) - -> ValueRef; - pub fn LLVMConstSRem(LHSConstant: ValueRef, RHSConstant: ValueRef) - -> ValueRef; - pub fn LLVMConstFRem(LHSConstant: ValueRef, RHSConstant: ValueRef) - -> ValueRef; - pub fn LLVMConstAnd(LHSConstant: ValueRef, RHSConstant: ValueRef) - -> ValueRef; - pub fn LLVMConstOr(LHSConstant: ValueRef, RHSConstant: ValueRef) - -> ValueRef; - pub fn LLVMConstXor(LHSConstant: ValueRef, RHSConstant: ValueRef) - -> ValueRef; - pub fn LLVMConstShl(LHSConstant: ValueRef, RHSConstant: ValueRef) - -> ValueRef; - pub fn LLVMConstLShr(LHSConstant: ValueRef, RHSConstant: ValueRef) - -> ValueRef; - pub fn LLVMConstAShr(LHSConstant: ValueRef, RHSConstant: ValueRef) - -> ValueRef; + pub fn LLVMConstAdd(LHSConstant: ValueRef, RHSConstant: ValueRef) -> ValueRef; + pub fn LLVMConstNSWAdd(LHSConstant: ValueRef, RHSConstant: ValueRef) -> ValueRef; + pub fn LLVMConstNUWAdd(LHSConstant: ValueRef, RHSConstant: ValueRef) -> ValueRef; + pub fn LLVMConstFAdd(LHSConstant: ValueRef, RHSConstant: ValueRef) -> ValueRef; + pub fn LLVMConstSub(LHSConstant: ValueRef, RHSConstant: ValueRef) -> ValueRef; + pub fn LLVMConstNSWSub(LHSConstant: ValueRef, RHSConstant: ValueRef) -> ValueRef; + pub fn LLVMConstNUWSub(LHSConstant: ValueRef, RHSConstant: ValueRef) -> ValueRef; + pub fn LLVMConstFSub(LHSConstant: ValueRef, RHSConstant: ValueRef) -> ValueRef; + pub fn LLVMConstMul(LHSConstant: ValueRef, RHSConstant: ValueRef) -> ValueRef; + pub fn LLVMConstNSWMul(LHSConstant: ValueRef, RHSConstant: ValueRef) -> ValueRef; + pub fn LLVMConstNUWMul(LHSConstant: ValueRef, RHSConstant: ValueRef) -> ValueRef; + pub fn LLVMConstFMul(LHSConstant: ValueRef, RHSConstant: ValueRef) -> ValueRef; + pub fn LLVMConstUDiv(LHSConstant: ValueRef, RHSConstant: ValueRef) -> ValueRef; + pub fn LLVMConstSDiv(LHSConstant: ValueRef, RHSConstant: ValueRef) -> ValueRef; + pub fn LLVMConstExactSDiv(LHSConstant: ValueRef, RHSConstant: ValueRef) -> ValueRef; + pub fn LLVMConstFDiv(LHSConstant: ValueRef, RHSConstant: ValueRef) -> ValueRef; + pub fn LLVMConstURem(LHSConstant: ValueRef, RHSConstant: ValueRef) -> ValueRef; + pub fn LLVMConstSRem(LHSConstant: ValueRef, RHSConstant: ValueRef) -> ValueRef; + pub fn LLVMConstFRem(LHSConstant: ValueRef, RHSConstant: ValueRef) -> ValueRef; + pub fn LLVMConstAnd(LHSConstant: ValueRef, RHSConstant: ValueRef) -> ValueRef; + pub fn LLVMConstOr(LHSConstant: ValueRef, RHSConstant: ValueRef) -> ValueRef; + pub fn LLVMConstXor(LHSConstant: ValueRef, RHSConstant: ValueRef) -> ValueRef; + pub fn LLVMConstShl(LHSConstant: ValueRef, RHSConstant: ValueRef) -> ValueRef; + pub fn LLVMConstLShr(LHSConstant: ValueRef, RHSConstant: ValueRef) -> ValueRef; + pub fn LLVMConstAShr(LHSConstant: ValueRef, RHSConstant: ValueRef) -> ValueRef; pub fn LLVMConstGEP(ConstantVal: ValueRef, ConstantIndices: *const ValueRef, NumIndices: c_uint) @@ -740,51 +689,29 @@ extern { ConstantIndices: *const ValueRef, NumIndices: c_uint) -> ValueRef; - pub fn LLVMConstTrunc(ConstantVal: ValueRef, ToType: TypeRef) - -> ValueRef; - pub fn LLVMConstSExt(ConstantVal: ValueRef, ToType: TypeRef) - -> ValueRef; - pub fn LLVMConstZExt(ConstantVal: ValueRef, ToType: TypeRef) - -> ValueRef; - pub fn LLVMConstFPTrunc(ConstantVal: ValueRef, ToType: TypeRef) - -> ValueRef; - pub fn LLVMConstFPExt(ConstantVal: ValueRef, ToType: TypeRef) - -> ValueRef; - pub fn LLVMConstUIToFP(ConstantVal: ValueRef, ToType: TypeRef) - -> ValueRef; - pub fn LLVMConstSIToFP(ConstantVal: ValueRef, ToType: TypeRef) - -> ValueRef; - pub fn LLVMConstFPToUI(ConstantVal: ValueRef, ToType: TypeRef) - -> ValueRef; - pub fn LLVMConstFPToSI(ConstantVal: ValueRef, ToType: TypeRef) - -> ValueRef; - pub fn LLVMConstPtrToInt(ConstantVal: ValueRef, ToType: TypeRef) - -> ValueRef; - pub fn LLVMConstIntToPtr(ConstantVal: ValueRef, ToType: TypeRef) - -> ValueRef; - pub fn LLVMConstBitCast(ConstantVal: ValueRef, ToType: TypeRef) - -> ValueRef; - pub fn LLVMConstZExtOrBitCast(ConstantVal: ValueRef, ToType: TypeRef) - -> ValueRef; - pub fn LLVMConstSExtOrBitCast(ConstantVal: ValueRef, ToType: TypeRef) - -> ValueRef; - pub fn LLVMConstTruncOrBitCast(ConstantVal: ValueRef, ToType: TypeRef) - -> ValueRef; - pub fn LLVMConstPointerCast(ConstantVal: ValueRef, ToType: TypeRef) - -> ValueRef; - pub fn LLVMConstIntCast(ConstantVal: ValueRef, - ToType: TypeRef, - isSigned: Bool) - -> ValueRef; - pub fn LLVMConstFPCast(ConstantVal: ValueRef, ToType: TypeRef) - -> ValueRef; + pub fn LLVMConstTrunc(ConstantVal: ValueRef, ToType: TypeRef) -> ValueRef; + pub fn LLVMConstSExt(ConstantVal: ValueRef, ToType: TypeRef) -> ValueRef; + pub fn LLVMConstZExt(ConstantVal: ValueRef, ToType: TypeRef) -> ValueRef; + pub fn LLVMConstFPTrunc(ConstantVal: ValueRef, ToType: TypeRef) -> ValueRef; + pub fn LLVMConstFPExt(ConstantVal: ValueRef, ToType: TypeRef) -> ValueRef; + pub fn LLVMConstUIToFP(ConstantVal: ValueRef, ToType: TypeRef) -> ValueRef; + pub fn LLVMConstSIToFP(ConstantVal: ValueRef, ToType: TypeRef) -> ValueRef; + pub fn LLVMConstFPToUI(ConstantVal: ValueRef, ToType: TypeRef) -> ValueRef; + pub fn LLVMConstFPToSI(ConstantVal: ValueRef, ToType: TypeRef) -> ValueRef; + pub fn LLVMConstPtrToInt(ConstantVal: ValueRef, ToType: TypeRef) -> ValueRef; + pub fn LLVMConstIntToPtr(ConstantVal: ValueRef, ToType: TypeRef) -> ValueRef; + pub fn LLVMConstBitCast(ConstantVal: ValueRef, ToType: TypeRef) -> ValueRef; + pub fn LLVMConstZExtOrBitCast(ConstantVal: ValueRef, ToType: TypeRef) -> ValueRef; + pub fn LLVMConstSExtOrBitCast(ConstantVal: ValueRef, ToType: TypeRef) -> ValueRef; + pub fn LLVMConstTruncOrBitCast(ConstantVal: ValueRef, ToType: TypeRef) -> ValueRef; + pub fn LLVMConstPointerCast(ConstantVal: ValueRef, ToType: TypeRef) -> ValueRef; + pub fn LLVMConstIntCast(ConstantVal: ValueRef, ToType: TypeRef, isSigned: Bool) -> ValueRef; + pub fn LLVMConstFPCast(ConstantVal: ValueRef, ToType: TypeRef) -> ValueRef; pub fn LLVMConstSelect(ConstantCondition: ValueRef, ConstantIfTrue: ValueRef, ConstantIfFalse: ValueRef) -> ValueRef; - pub fn LLVMConstExtractElement(VectorConstant: ValueRef, - IndexConstant: ValueRef) - -> ValueRef; + pub fn LLVMConstExtractElement(VectorConstant: ValueRef, IndexConstant: ValueRef) -> ValueRef; pub fn LLVMConstInsertElement(VectorConstant: ValueRef, ElementValueConstant: ValueRef, IndexConstant: ValueRef) @@ -812,7 +739,7 @@ extern { - /* Operations on global variables, functions, and aliases (globals) */ + // Operations on global variables, functions, and aliases (globals) pub fn LLVMGetGlobalParent(Global: ValueRef) -> ModuleRef; pub fn LLVMIsDeclaration(Global: ValueRef) -> Bool; pub fn LLVMRustGetLinkage(Global: ValueRef) -> Linkage; @@ -823,52 +750,41 @@ extern { pub fn LLVMSetVisibility(Global: ValueRef, Viz: c_uint); pub fn LLVMGetAlignment(Global: ValueRef) -> c_uint; pub fn LLVMSetAlignment(Global: ValueRef, Bytes: c_uint); - pub fn LLVMSetDLLStorageClass(V: ValueRef, - C: DLLStorageClass); + pub fn LLVMSetDLLStorageClass(V: ValueRef, C: DLLStorageClass); - /* Operations on global variables */ + // Operations on global variables pub fn LLVMIsAGlobalVariable(GlobalVar: ValueRef) -> ValueRef; - pub fn LLVMAddGlobal(M: ModuleRef, Ty: TypeRef, Name: *const c_char) - -> ValueRef; + pub fn LLVMAddGlobal(M: ModuleRef, Ty: TypeRef, Name: *const c_char) -> ValueRef; pub fn LLVMAddGlobalInAddressSpace(M: ModuleRef, Ty: TypeRef, Name: *const c_char, AddressSpace: c_uint) -> ValueRef; - pub fn LLVMGetNamedGlobal(M: ModuleRef, - Name: *const c_char) - -> ValueRef; - pub fn LLVMRustGetOrInsertGlobal(M: ModuleRef, - Name: *const c_char, - T: TypeRef) - -> ValueRef; + pub fn LLVMGetNamedGlobal(M: ModuleRef, Name: *const c_char) -> ValueRef; + pub fn LLVMRustGetOrInsertGlobal(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; pub fn LLVMGetPreviousGlobal(GlobalVar: ValueRef) -> ValueRef; pub fn LLVMDeleteGlobal(GlobalVar: ValueRef); pub fn LLVMGetInitializer(GlobalVar: ValueRef) -> ValueRef; - pub fn LLVMSetInitializer(GlobalVar: ValueRef, - ConstantVal: ValueRef); + pub fn LLVMSetInitializer(GlobalVar: ValueRef, ConstantVal: ValueRef); pub fn LLVMIsThreadLocal(GlobalVar: ValueRef) -> Bool; pub fn LLVMSetThreadLocal(GlobalVar: ValueRef, IsThreadLocal: Bool); pub fn LLVMIsGlobalConstant(GlobalVar: ValueRef) -> Bool; pub fn LLVMSetGlobalConstant(GlobalVar: ValueRef, IsConstant: Bool); pub fn LLVMRustGetNamedValue(M: ModuleRef, Name: *const c_char) -> ValueRef; - /* Operations on aliases */ + // Operations on aliases pub fn LLVMAddAlias(M: ModuleRef, Ty: TypeRef, Aliasee: ValueRef, Name: *const c_char) -> ValueRef; - /* Operations on functions */ - pub fn LLVMAddFunction(M: ModuleRef, - Name: *const c_char, - FunctionTy: TypeRef) - -> ValueRef; + // Operations on functions + pub fn LLVMAddFunction(M: ModuleRef, Name: *const c_char, FunctionTy: TypeRef) -> ValueRef; pub fn LLVMGetNamedFunction(M: ModuleRef, Name: *const c_char) -> ValueRef; pub fn LLVMGetFirstFunction(M: ModuleRef) -> ValueRef; pub fn LLVMGetLastFunction(M: ModuleRef) -> ValueRef; @@ -887,19 +803,16 @@ extern { pub fn LLVMRustAddDereferenceableAttr(Fn: ValueRef, index: c_uint, bytes: u64); pub fn LLVMRustAddFunctionAttribute(Fn: ValueRef, index: c_uint, PA: u64); pub fn LLVMRustAddFunctionAttrString(Fn: ValueRef, index: c_uint, Name: *const c_char); - pub fn LLVMRustAddFunctionAttrStringValue(Fn: ValueRef, index: c_uint, + pub fn LLVMRustAddFunctionAttrStringValue(Fn: ValueRef, + index: c_uint, Name: *const c_char, Value: *const c_char); - pub fn LLVMRustRemoveFunctionAttributes(Fn: ValueRef, - index: c_uint, - attr: u64); - pub fn LLVMRustRemoveFunctionAttrString(Fn: ValueRef, - index: c_uint, - Name: *const c_char); + pub fn LLVMRustRemoveFunctionAttributes(Fn: ValueRef, index: c_uint, attr: u64); + pub fn LLVMRustRemoveFunctionAttrString(Fn: ValueRef, index: c_uint, Name: *const c_char); pub fn LLVMGetFunctionAttr(Fn: ValueRef) -> c_uint; pub fn LLVMRemoveFunctionAttr(Fn: ValueRef, val: c_uint); - /* Operations on parameters */ + // Operations on parameters pub fn LLVMCountParams(Fn: ValueRef) -> c_uint; pub fn LLVMGetParams(Fn: ValueRef, Params: *const ValueRef); pub fn LLVMGetParam(Fn: ValueRef, Index: c_uint) -> ValueRef; @@ -913,7 +826,7 @@ extern { pub fn LLVMGetAttribute(Arg: ValueRef) -> c_uint; pub fn LLVMSetParamAlignment(Arg: ValueRef, align: c_uint); - /* Operations on basic blocks */ + // Operations on basic blocks pub fn LLVMBasicBlockAsValue(BB: BasicBlockRef) -> ValueRef; pub fn LLVMValueIsBasicBlock(Val: ValueRef) -> Bool; pub fn LLVMValueAsBasicBlock(Val: ValueRef) -> BasicBlockRef; @@ -936,13 +849,11 @@ extern { -> BasicBlockRef; pub fn LLVMDeleteBasicBlock(BB: BasicBlockRef); - pub fn LLVMMoveBasicBlockAfter(BB: BasicBlockRef, - MoveAfter: BasicBlockRef); + pub fn LLVMMoveBasicBlockAfter(BB: BasicBlockRef, MoveAfter: BasicBlockRef); - pub fn LLVMMoveBasicBlockBefore(BB: BasicBlockRef, - MoveBefore: BasicBlockRef); + pub fn LLVMMoveBasicBlockBefore(BB: BasicBlockRef, MoveBefore: BasicBlockRef); - /* Operations on instructions */ + // Operations on instructions pub fn LLVMGetInstructionParent(Inst: ValueRef) -> BasicBlockRef; pub fn LLVMGetFirstInstruction(BB: BasicBlockRef) -> ValueRef; pub fn LLVMGetLastInstruction(BB: BasicBlockRef) -> ValueRef; @@ -950,53 +861,37 @@ extern { pub fn LLVMGetPreviousInstruction(Inst: ValueRef) -> ValueRef; pub fn LLVMInstructionEraseFromParent(Inst: ValueRef); - /* Operations on call sites */ + // Operations on call sites pub fn LLVMSetInstructionCallConv(Instr: ValueRef, CC: c_uint); pub fn LLVMGetInstructionCallConv(Instr: ValueRef) -> c_uint; - pub fn LLVMAddInstrAttribute(Instr: ValueRef, - index: c_uint, - IA: c_uint); - pub fn LLVMRemoveInstrAttribute(Instr: ValueRef, - index: c_uint, - IA: c_uint); - pub fn LLVMSetInstrParamAlignment(Instr: ValueRef, - index: c_uint, - align: c_uint); - pub fn LLVMRustAddCallSiteAttribute(Instr: ValueRef, - index: c_uint, - Val: u64); - pub fn LLVMRustAddDereferenceableCallSiteAttr(Instr: ValueRef, - index: c_uint, - bytes: u64); - - /* Operations on call instructions (only) */ + pub fn LLVMAddInstrAttribute(Instr: ValueRef, index: c_uint, IA: c_uint); + pub fn LLVMRemoveInstrAttribute(Instr: ValueRef, index: c_uint, IA: c_uint); + pub fn LLVMSetInstrParamAlignment(Instr: ValueRef, index: c_uint, align: c_uint); + pub fn LLVMRustAddCallSiteAttribute(Instr: ValueRef, index: c_uint, Val: u64); + pub fn LLVMRustAddDereferenceableCallSiteAttr(Instr: ValueRef, index: c_uint, bytes: u64); + + // Operations on call instructions (only) pub fn LLVMIsTailCall(CallInst: ValueRef) -> Bool; pub fn LLVMSetTailCall(CallInst: ValueRef, IsTailCall: Bool); - /* Operations on load/store instructions (only) */ + // Operations on load/store instructions (only) pub fn LLVMGetVolatile(MemoryAccessInst: ValueRef) -> Bool; pub fn LLVMSetVolatile(MemoryAccessInst: ValueRef, volatile: Bool); - /* Operations on phi nodes */ + // Operations on phi nodes pub fn LLVMAddIncoming(PhiNode: ValueRef, IncomingValues: *const ValueRef, IncomingBlocks: *const BasicBlockRef, Count: c_uint); pub fn LLVMCountIncoming(PhiNode: ValueRef) -> c_uint; - pub fn LLVMGetIncomingValue(PhiNode: ValueRef, Index: c_uint) - -> ValueRef; - pub fn LLVMGetIncomingBlock(PhiNode: ValueRef, Index: c_uint) - -> BasicBlockRef; + pub fn LLVMGetIncomingValue(PhiNode: ValueRef, Index: c_uint) -> ValueRef; + pub fn LLVMGetIncomingBlock(PhiNode: ValueRef, Index: c_uint) -> BasicBlockRef; - /* Instruction builders */ + // Instruction builders pub fn LLVMCreateBuilderInContext(C: ContextRef) -> BuilderRef; - pub fn LLVMPositionBuilder(Builder: BuilderRef, - Block: BasicBlockRef, - Instr: ValueRef); - pub fn LLVMPositionBuilderBefore(Builder: BuilderRef, - Instr: ValueRef); - pub fn LLVMPositionBuilderAtEnd(Builder: BuilderRef, - Block: BasicBlockRef); + pub fn LLVMPositionBuilder(Builder: BuilderRef, Block: BasicBlockRef, Instr: ValueRef); + pub fn LLVMPositionBuilderBefore(Builder: BuilderRef, Instr: ValueRef); + pub fn LLVMPositionBuilderAtEnd(Builder: BuilderRef, Block: BasicBlockRef); pub fn LLVMGetInsertBlock(Builder: BuilderRef) -> BasicBlockRef; pub fn LLVMClearInsertionPosition(Builder: BuilderRef); pub fn LLVMInsertIntoBuilder(Builder: BuilderRef, Instr: ValueRef); @@ -1005,18 +900,15 @@ extern { Name: *const c_char); pub fn LLVMDisposeBuilder(Builder: BuilderRef); - /* Metadata */ + // Metadata pub fn LLVMSetCurrentDebugLocation(Builder: BuilderRef, L: ValueRef); pub fn LLVMGetCurrentDebugLocation(Builder: BuilderRef) -> ValueRef; pub fn LLVMSetInstDebugLocation(Builder: BuilderRef, Inst: ValueRef); - /* Terminators */ + // Terminators pub fn LLVMBuildRetVoid(B: BuilderRef) -> ValueRef; pub fn LLVMBuildRet(B: BuilderRef, V: ValueRef) -> ValueRef; - pub fn LLVMBuildAggregateRet(B: BuilderRef, - RetVals: *const ValueRef, - N: c_uint) - -> ValueRef; + pub fn LLVMBuildAggregateRet(B: BuilderRef, RetVals: *const ValueRef, N: c_uint) -> ValueRef; pub fn LLVMBuildBr(B: BuilderRef, Dest: BasicBlockRef) -> ValueRef; pub fn LLVMBuildCondBr(B: BuilderRef, If: ValueRef, @@ -1028,10 +920,7 @@ extern { Else: BasicBlockRef, NumCases: c_uint) -> ValueRef; - pub fn LLVMBuildIndirectBr(B: BuilderRef, - Addr: ValueRef, - NumDests: c_uint) - -> ValueRef; + pub fn LLVMBuildIndirectBr(B: BuilderRef, Addr: ValueRef, NumDests: c_uint) -> ValueRef; pub fn LLVMRustBuildInvoke(B: BuilderRef, Fn: ValueRef, Args: *const ValueRef, @@ -1055,42 +944,41 @@ extern { ParentPad: ValueRef, ArgCnt: c_uint, Args: *const ValueRef, - Name: *const c_char) -> ValueRef; + Name: *const c_char) + -> ValueRef; pub fn LLVMRustBuildCleanupRet(B: BuilderRef, CleanupPad: ValueRef, - UnwindBB: BasicBlockRef) -> ValueRef; + UnwindBB: BasicBlockRef) + -> ValueRef; pub fn LLVMRustBuildCatchPad(B: BuilderRef, ParentPad: ValueRef, ArgCnt: c_uint, Args: *const ValueRef, - Name: *const c_char) -> ValueRef; - pub fn LLVMRustBuildCatchRet(B: BuilderRef, - Pad: ValueRef, - BB: BasicBlockRef) -> ValueRef; + Name: *const c_char) + -> ValueRef; + pub fn LLVMRustBuildCatchRet(B: BuilderRef, Pad: ValueRef, BB: BasicBlockRef) -> ValueRef; pub fn LLVMRustBuildCatchSwitch(Builder: BuilderRef, ParentPad: ValueRef, BB: BasicBlockRef, NumHandlers: c_uint, - Name: *const c_char) -> ValueRef; - pub fn LLVMRustAddHandler(CatchSwitch: ValueRef, - Handler: BasicBlockRef); + Name: *const c_char) + -> ValueRef; + pub fn LLVMRustAddHandler(CatchSwitch: ValueRef, Handler: BasicBlockRef); pub fn LLVMRustSetPersonalityFn(B: BuilderRef, Pers: ValueRef); - /* Add a case to the switch instruction */ - pub fn LLVMAddCase(Switch: ValueRef, - OnVal: ValueRef, - Dest: BasicBlockRef); + // Add a case to the switch instruction + pub fn LLVMAddCase(Switch: ValueRef, OnVal: ValueRef, Dest: BasicBlockRef); - /* Add a destination to the indirectbr instruction */ + // Add a destination to the indirectbr instruction pub fn LLVMAddDestination(IndirectBr: ValueRef, Dest: BasicBlockRef); - /* Add a clause to the landing pad instruction */ + // Add a clause to the landing pad instruction pub fn LLVMAddClause(LandingPad: ValueRef, ClauseVal: ValueRef); - /* Set the cleanup on a landing pad instruction */ + // Set the cleanup on a landing pad instruction pub fn LLVMSetCleanup(LandingPad: ValueRef, Val: Bool); - /* Arithmetic */ + // Arithmetic pub fn LLVMBuildAdd(B: BuilderRef, LHS: ValueRef, RHS: ValueRef, @@ -1210,7 +1098,7 @@ extern { LHS: ValueRef, RHS: ValueRef, Name: *const c_char) - -> ValueRef; + -> ValueRef; pub fn LLVMBuildXor(B: BuilderRef, LHS: ValueRef, RHS: ValueRef, @@ -1222,29 +1110,19 @@ extern { RHS: ValueRef, Name: *const c_char) -> ValueRef; - pub fn LLVMBuildNeg(B: BuilderRef, V: ValueRef, Name: *const c_char) - -> ValueRef; - pub fn LLVMBuildNSWNeg(B: BuilderRef, V: ValueRef, Name: *const c_char) - -> ValueRef; - pub fn LLVMBuildNUWNeg(B: BuilderRef, V: ValueRef, Name: *const c_char) - -> ValueRef; - pub fn LLVMBuildFNeg(B: BuilderRef, V: ValueRef, Name: *const c_char) - -> ValueRef; - pub fn LLVMBuildNot(B: BuilderRef, V: ValueRef, Name: *const c_char) - -> ValueRef; + pub fn LLVMBuildNeg(B: BuilderRef, V: ValueRef, Name: *const c_char) -> ValueRef; + pub fn LLVMBuildNSWNeg(B: BuilderRef, V: ValueRef, Name: *const c_char) -> ValueRef; + pub fn LLVMBuildNUWNeg(B: BuilderRef, V: ValueRef, Name: *const c_char) -> ValueRef; + pub fn LLVMBuildFNeg(B: BuilderRef, V: ValueRef, Name: *const c_char) -> ValueRef; + pub fn LLVMBuildNot(B: BuilderRef, V: ValueRef, Name: *const c_char) -> ValueRef; pub fn LLVMRustSetHasUnsafeAlgebra(Instr: ValueRef); - /* Memory */ - pub fn LLVMBuildAlloca(B: BuilderRef, Ty: TypeRef, Name: *const c_char) - -> ValueRef; + // Memory + pub fn LLVMBuildAlloca(B: BuilderRef, Ty: TypeRef, Name: *const c_char) -> ValueRef; pub fn LLVMBuildFree(B: BuilderRef, PointerVal: ValueRef) -> ValueRef; - pub fn LLVMBuildLoad(B: BuilderRef, - PointerVal: ValueRef, - Name: *const c_char) - -> ValueRef; + pub fn LLVMBuildLoad(B: BuilderRef, PointerVal: ValueRef, Name: *const c_char) -> ValueRef; - pub fn LLVMBuildStore(B: BuilderRef, Val: ValueRef, Ptr: ValueRef) - -> ValueRef; + pub fn LLVMBuildStore(B: BuilderRef, Val: ValueRef, Ptr: ValueRef) -> ValueRef; pub fn LLVMBuildGEP(B: BuilderRef, Pointer: ValueRef, @@ -1272,7 +1150,7 @@ extern { Name: *const c_char) -> ValueRef; - /* Casts */ + // Casts pub fn LLVMBuildTrunc(B: BuilderRef, Val: ValueRef, DestTy: TypeRef, @@ -1352,7 +1230,8 @@ extern { Op: Opcode, Val: ValueRef, DestTy: TypeRef, - Name: *const c_char) -> ValueRef; + Name: *const c_char) + -> ValueRef; pub fn LLVMBuildPointerCast(B: BuilderRef, Val: ValueRef, DestTy: TypeRef, @@ -1369,7 +1248,7 @@ extern { Name: *const c_char) -> ValueRef; - /* Comparisons */ + // Comparisons pub fn LLVMBuildICmp(B: BuilderRef, Op: c_uint, LHS: ValueRef, @@ -1383,9 +1262,8 @@ extern { Name: *const c_char) -> ValueRef; - /* Miscellaneous instructions */ - pub fn LLVMBuildPhi(B: BuilderRef, Ty: TypeRef, Name: *const c_char) - -> ValueRef; + // Miscellaneous instructions + pub fn LLVMBuildPhi(B: BuilderRef, Ty: TypeRef, Name: *const c_char) -> ValueRef; pub fn LLVMRustBuildCall(B: BuilderRef, Fn: ValueRef, Args: *const ValueRef, @@ -1433,17 +1311,15 @@ extern { Name: *const c_char) -> ValueRef; - pub fn LLVMBuildIsNull(B: BuilderRef, Val: ValueRef, Name: *const c_char) - -> ValueRef; - pub fn LLVMBuildIsNotNull(B: BuilderRef, Val: ValueRef, Name: *const c_char) - -> ValueRef; + pub fn LLVMBuildIsNull(B: BuilderRef, Val: ValueRef, Name: *const c_char) -> ValueRef; + pub fn LLVMBuildIsNotNull(B: BuilderRef, Val: ValueRef, Name: *const c_char) -> ValueRef; pub fn LLVMBuildPtrDiff(B: BuilderRef, LHS: ValueRef, RHS: ValueRef, Name: *const c_char) -> ValueRef; - /* Atomic Operations */ + // Atomic Operations pub fn LLVMRustBuildAtomicLoad(B: BuilderRef, PointerVal: ValueRef, Name: *const c_char, @@ -1480,7 +1356,7 @@ extern { Scope: SynchronizationScope); - /* Selected entries from the downcasts. */ + // Selected entries from the downcasts. pub fn LLVMIsATerminatorInst(Inst: ValueRef) -> ValueRef; pub fn LLVMIsAStoreInst(Inst: ValueRef) -> ValueRef; @@ -1490,22 +1366,18 @@ extern { /// Creates target data from a target layout string. pub fn LLVMCreateTargetData(StringRep: *const c_char) -> TargetDataRef; /// Number of bytes clobbered when doing a Store to *T. - pub fn LLVMStoreSizeOfType(TD: TargetDataRef, Ty: TypeRef) - -> c_ulonglong; + pub fn LLVMStoreSizeOfType(TD: TargetDataRef, Ty: TypeRef) -> c_ulonglong; /// Number of bytes clobbered when doing a Store to *T. - pub fn LLVMSizeOfTypeInBits(TD: TargetDataRef, Ty: TypeRef) - -> c_ulonglong; + pub fn LLVMSizeOfTypeInBits(TD: TargetDataRef, Ty: TypeRef) -> c_ulonglong; /// Distance between successive elements in an array of T. Includes ABI padding. pub fn LLVMABISizeOfType(TD: TargetDataRef, Ty: TypeRef) -> c_ulonglong; /// Returns the preferred alignment of a type. - pub fn LLVMPreferredAlignmentOfType(TD: TargetDataRef, Ty: TypeRef) - -> c_uint; + pub fn LLVMPreferredAlignmentOfType(TD: TargetDataRef, Ty: TypeRef) -> c_uint; /// Returns the minimum alignment of a type. - pub fn LLVMABIAlignmentOfType(TD: TargetDataRef, Ty: TypeRef) - -> c_uint; + pub fn LLVMABIAlignmentOfType(TD: TargetDataRef, Ty: TypeRef) -> c_uint; /// Computes the byte offset of the indexed struct element for a /// target. @@ -1515,8 +1387,7 @@ extern { -> c_ulonglong; /// Returns the minimum alignment of a type when part of a call frame. - pub fn LLVMCallFrameAlignmentOfType(TD: TargetDataRef, Ty: TypeRef) - -> c_uint; + pub fn LLVMCallFrameAlignmentOfType(TD: TargetDataRef, Ty: TypeRef) -> c_uint; /// Disposes target data. pub fn LLVMDisposeTargetData(TD: TargetDataRef); @@ -1525,8 +1396,7 @@ extern { pub fn LLVMCreatePassManager() -> PassManagerRef; /// Creates a function-by-function pass manager - pub fn LLVMCreateFunctionPassManagerForModule(M: ModuleRef) - -> PassManagerRef; + pub fn LLVMCreateFunctionPassManagerForModule(M: ModuleRef) -> PassManagerRef; /// Disposes a pass manager. pub fn LLVMDisposePassManager(PM: PassManagerRef); @@ -1535,8 +1405,7 @@ extern { pub fn LLVMRunPassManager(PM: PassManagerRef, M: ModuleRef) -> Bool; /// Runs the function passes on the provided function. - pub fn LLVMRunFunctionPassManager(FPM: PassManagerRef, F: ValueRef) - -> Bool; + pub fn LLVMRunFunctionPassManager(FPM: PassManagerRef, F: ValueRef) -> Bool; /// Initializes all the function passes scheduled in the manager pub fn LLVMInitializeFunctionPassManager(FPM: PassManagerRef) -> Bool; @@ -1589,38 +1458,28 @@ extern { pub fn LLVMPassManagerBuilderDispose(PMB: PassManagerBuilderRef); pub fn LLVMPassManagerBuilderSetOptLevel(PMB: PassManagerBuilderRef, OptimizationLevel: c_uint); - pub fn LLVMPassManagerBuilderSetSizeLevel(PMB: PassManagerBuilderRef, - Value: Bool); - pub fn LLVMPassManagerBuilderSetDisableUnitAtATime( - PMB: PassManagerBuilderRef, - Value: Bool); - pub fn LLVMPassManagerBuilderSetDisableUnrollLoops( - PMB: PassManagerBuilderRef, - Value: Bool); - pub fn LLVMPassManagerBuilderSetDisableSimplifyLibCalls( - PMB: PassManagerBuilderRef, - Value: Bool); - pub fn LLVMPassManagerBuilderUseInlinerWithThreshold( - PMB: PassManagerBuilderRef, - threshold: c_uint); - pub fn LLVMPassManagerBuilderPopulateModulePassManager( - PMB: PassManagerBuilderRef, - PM: PassManagerRef); - - pub fn LLVMPassManagerBuilderPopulateFunctionPassManager( - PMB: PassManagerBuilderRef, - PM: PassManagerRef); - pub fn LLVMPassManagerBuilderPopulateLTOPassManager( - PMB: PassManagerBuilderRef, - PM: PassManagerRef, - Internalize: Bool, - RunInliner: Bool); + pub fn LLVMPassManagerBuilderSetSizeLevel(PMB: PassManagerBuilderRef, Value: Bool); + pub fn LLVMPassManagerBuilderSetDisableUnitAtATime(PMB: PassManagerBuilderRef, Value: Bool); + pub fn LLVMPassManagerBuilderSetDisableUnrollLoops(PMB: PassManagerBuilderRef, Value: Bool); + pub fn LLVMPassManagerBuilderSetDisableSimplifyLibCalls(PMB: PassManagerBuilderRef, + Value: Bool); + pub fn LLVMPassManagerBuilderUseInlinerWithThreshold(PMB: PassManagerBuilderRef, + threshold: c_uint); + pub fn LLVMPassManagerBuilderPopulateModulePassManager(PMB: PassManagerBuilderRef, + PM: PassManagerRef); + + pub fn LLVMPassManagerBuilderPopulateFunctionPassManager(PMB: PassManagerBuilderRef, + PM: PassManagerRef); + pub fn LLVMPassManagerBuilderPopulateLTOPassManager(PMB: PassManagerBuilderRef, + PM: PassManagerRef, + Internalize: Bool, + RunInliner: Bool); /// Destroys a memory buffer. pub fn LLVMDisposeMemoryBuffer(MemBuf: MemoryBufferRef); - /* Stuff that's in rustllvm/ because it's not upstream yet. */ + // Stuff that's in rustllvm/ because it's not upstream yet. /// Opens an object file. pub fn LLVMCreateObjectFile(MemBuf: MemoryBufferRef) -> ObjectFileRef; @@ -1633,9 +1492,7 @@ extern { pub fn LLVMDisposeSectionIterator(SI: SectionIteratorRef); /// Returns true if the section iterator is at the end of the section /// list: - pub fn LLVMIsSectionIteratorAtEnd(ObjFile: ObjectFileRef, - SI: SectionIteratorRef) - -> Bool; + pub fn LLVMIsSectionIteratorAtEnd(ObjFile: ObjectFileRef, SI: SectionIteratorRef) -> Bool; /// Moves the section iterator to point to the next section. pub fn LLVMMoveToNextSection(SI: SectionIteratorRef); /// Returns the current section size. @@ -1645,8 +1502,7 @@ extern { /// Reads the given file and returns it as a memory buffer. Use /// LLVMDisposeMemoryBuffer() to get rid of it. - pub fn LLVMRustCreateMemoryBufferWithContentsOfFile(Path: *const c_char) - -> MemoryBufferRef; + pub fn LLVMRustCreateMemoryBufferWithContentsOfFile(Path: *const c_char) -> MemoryBufferRef; /// Borrows the contents of the memory buffer (doesn't copy it) pub fn LLVMCreateMemoryBufferWithMemoryRange(InputData: *const c_char, InputDataLength: size_t, @@ -1695,9 +1551,7 @@ extern { pub fn LLVMRustVersionMajor() -> u32; pub fn LLVMRustVersionMinor() -> u32; - pub fn LLVMRustAddModuleFlag(M: ModuleRef, - name: *const c_char, - value: u32); + pub fn LLVMRustAddModuleFlag(M: ModuleRef, name: *const c_char, value: u32); pub fn LLVMRustDIBuilderCreate(M: ModuleRef) -> DIBuilderRef; @@ -1751,11 +1605,11 @@ extern { -> DIBasicType; pub fn LLVMRustDIBuilderCreatePointerType(Builder: DIBuilderRef, - PointeeTy: DIType, - SizeInBits: u64, - AlignInBits: u64, - Name: *const c_char) - -> DIDerivedType; + PointeeTy: DIType, + SizeInBits: u64, + AlignInBits: u64, + Name: *const c_char) + -> DIDerivedType; pub fn LLVMRustDIBuilderCreateStructType(Builder: DIBuilderRef, Scope: DIDescriptor, @@ -1817,8 +1671,6 @@ extern { Ty: DIType, AlwaysPreserve: bool, Flags: c_uint, - AddrOps: *const i64, - AddrOpsCount: c_uint, ArgNo: c_uint) -> DIVariable; @@ -1855,15 +1707,6 @@ extern { InsertAtEnd: BasicBlockRef) -> ValueRef; - pub fn LLVMRustDIBuilderInsertDeclareBefore(Builder: DIBuilderRef, - Val: ValueRef, - VarInfo: DIVariable, - AddrOps: *const i64, - AddrOpsCount: c_uint, - DL: ValueRef, - InsertBefore: ValueRef) - -> ValueRef; - pub fn LLVMRustDIBuilderCreateEnumerator(Builder: DIBuilderRef, Name: *const c_char, Val: u64) @@ -1937,8 +1780,7 @@ extern { pub fn LLVMRustFindAndCreatePass(Pass: *const c_char) -> PassRef; pub fn LLVMRustAddPass(PM: PassManagerRef, Pass: PassRef); - pub fn LLVMRustHasFeature(T: TargetMachineRef, - s: *const c_char) -> bool; + pub fn LLVMRustHasFeature(T: TargetMachineRef, s: *const c_char) -> bool; pub fn LLVMRustPrintTargetCPUs(T: TargetMachineRef); pub fn LLVMRustPrintTargetFeatures(T: TargetMachineRef); @@ -1952,11 +1794,10 @@ extern { UseSoftFP: bool, PositionIndependentExecutable: bool, FunctionSections: bool, - DataSections: bool) -> TargetMachineRef; + DataSections: bool) + -> TargetMachineRef; pub fn LLVMRustDisposeTargetMachine(T: TargetMachineRef); - pub fn LLVMRustAddAnalysisPasses(T: TargetMachineRef, - PM: PassManagerRef, - M: ModuleRef); + pub fn LLVMRustAddAnalysisPasses(T: TargetMachineRef, PM: PassManagerRef, M: ModuleRef); pub fn LLVMRustAddBuilderLibraryInfo(PMB: PassManagerBuilderRef, M: ModuleRef, DisableSimplifyLibCalls: bool); @@ -1965,7 +1806,8 @@ extern { MergeFunctions: bool, SLPVectorize: bool, LoopVectorize: bool); - pub fn LLVMRustAddLibraryInfo(PM: PassManagerRef, M: ModuleRef, + pub fn LLVMRustAddLibraryInfo(PM: PassManagerRef, + M: ModuleRef, DisableSimplifyLibCalls: bool); pub fn LLVMRustRunFunctionPassManager(PM: PassManagerRef, M: ModuleRef); pub fn LLVMRustWriteOutputFile(T: TargetMachineRef, @@ -1974,35 +1816,25 @@ extern { Output: *const c_char, FileType: FileType) -> LLVMRustResult; - pub fn LLVMRustPrintModule(PM: PassManagerRef, - M: ModuleRef, - Output: *const c_char); + pub fn LLVMRustPrintModule(PM: PassManagerRef, M: ModuleRef, Output: *const c_char); pub fn LLVMRustSetLLVMOptions(Argc: c_int, Argv: *const *const c_char); pub fn LLVMRustPrintPasses(); pub fn LLVMRustSetNormalizedTarget(M: ModuleRef, triple: *const c_char); - pub fn LLVMRustAddAlwaysInlinePass(P: PassManagerBuilderRef, - AddLifetimes: bool); - pub fn LLVMRustLinkInExternalBitcode(M: ModuleRef, - bc: *const c_char, - len: size_t) -> bool; - pub fn LLVMRustRunRestrictionPass(M: ModuleRef, - syms: *const *const c_char, - len: size_t); + pub fn LLVMRustAddAlwaysInlinePass(P: PassManagerBuilderRef, AddLifetimes: bool); + pub fn LLVMRustLinkInExternalBitcode(M: ModuleRef, bc: *const c_char, len: size_t) -> bool; + pub fn LLVMRustRunRestrictionPass(M: ModuleRef, syms: *const *const c_char, len: size_t); pub fn LLVMRustMarkAllFunctionsNounwind(M: ModuleRef); pub fn LLVMRustOpenArchive(path: *const c_char) -> ArchiveRef; pub fn LLVMRustArchiveIteratorNew(AR: ArchiveRef) -> ArchiveIteratorRef; pub fn LLVMRustArchiveIteratorNext(AIR: ArchiveIteratorRef) -> ArchiveChildRef; - pub fn LLVMRustArchiveChildName(ACR: ArchiveChildRef, - size: *mut size_t) -> *const c_char; - pub fn LLVMRustArchiveChildData(ACR: ArchiveChildRef, - size: *mut size_t) -> *const c_char; + pub fn LLVMRustArchiveChildName(ACR: ArchiveChildRef, size: *mut size_t) -> *const c_char; + pub fn LLVMRustArchiveChildData(ACR: ArchiveChildRef, size: *mut size_t) -> *const c_char; pub fn LLVMRustArchiveChildFree(ACR: ArchiveChildRef); pub fn LLVMRustArchiveIteratorFree(AIR: ArchiveIteratorRef); pub fn LLVMRustDestroyArchive(AR: ArchiveRef); - pub fn LLVMRustGetSectionName(SI: SectionIteratorRef, - data: *mut *const c_char) -> size_t; + pub fn LLVMRustGetSectionName(SI: SectionIteratorRef, data: *mut *const c_char) -> size_t; pub fn LLVMRustWriteTwineToString(T: TwineRef, s: RustStringRef); @@ -2020,14 +1852,11 @@ extern { message_out: *mut TwineRef, instruction_out: *mut ValueRef); - pub fn LLVMRustWriteDiagnosticInfoToString(DI: DiagnosticInfoRef, - s: RustStringRef); + pub fn LLVMRustWriteDiagnosticInfoToString(DI: DiagnosticInfoRef, s: RustStringRef); pub fn LLVMGetDiagInfoSeverity(DI: DiagnosticInfoRef) -> DiagnosticSeverity; pub fn LLVMRustGetDiagInfoKind(DI: DiagnosticInfoRef) -> DiagnosticKind; - pub fn LLVMRustWriteDebugLocToString(C: ContextRef, - DL: DebugLocRef, - s: RustStringRef); + pub fn LLVMRustWriteDebugLocToString(C: ContextRef, DL: DebugLocRef, s: RustStringRef); pub fn LLVMRustSetInlineAsmDiagnosticHandler(C: ContextRef, H: InlineAsmDiagHandler, @@ -2039,15 +1868,15 @@ extern { NumMembers: size_t, Members: *const RustArchiveMemberRef, WriteSymbtab: bool, - Kind: ArchiveKind) -> - LLVMRustResult; + Kind: ArchiveKind) + -> LLVMRustResult; pub fn LLVMRustArchiveMemberNew(Filename: *const c_char, Name: *const c_char, - Child: ArchiveChildRef) -> RustArchiveMemberRef; + Child: ArchiveChildRef) + -> RustArchiveMemberRef; pub fn LLVMRustArchiveMemberFree(Member: RustArchiveMemberRef); - pub fn LLVMRustSetDataLayoutFromTargetMachine(M: ModuleRef, - TM: TargetMachineRef); + pub fn LLVMRustSetDataLayoutFromTargetMachine(M: ModuleRef, TM: TargetMachineRef); pub fn LLVMRustGetModuleDataLayout(M: ModuleRef) -> TargetDataRef; pub fn LLVMRustBuildOperandBundleDef(Name: *const c_char, @@ -2068,4 +1897,4 @@ extern { // during llvm-config? #[cfg(windows)] #[link(name = "ole32")] -extern {} +extern "C" {} diff --git a/src/librustc_llvm/lib.rs b/src/librustc_llvm/lib.rs index eb45d3d25c..da09bfa66d 100644 --- a/src/librustc_llvm/lib.rs +++ b/src/librustc_llvm/lib.rs @@ -31,7 +31,9 @@ #![feature(concat_idents)] extern crate libc; -#[macro_use] #[no_link] extern crate rustc_bitflags; +#[macro_use] +#[no_link] +extern crate rustc_bitflags; pub use self::IntPredicate::*; pub use self::RealPredicate::*; @@ -68,7 +70,7 @@ impl LLVMRustResult { #[derive(Copy, Clone, Default, Debug)] pub struct Attributes { regular: Attribute, - dereferenceable_bytes: u64 + dereferenceable_bytes: u64, } impl Attributes { @@ -96,10 +98,7 @@ impl Attributes { unsafe { self.regular.apply_llfn(idx, llfn); if self.dereferenceable_bytes != 0 { - LLVMRustAddDereferenceableAttr( - llfn, - idx.as_uint(), - self.dereferenceable_bytes); + LLVMRustAddDereferenceableAttr(llfn, idx.as_uint(), self.dereferenceable_bytes); } } } @@ -108,27 +107,23 @@ impl Attributes { unsafe { self.regular.apply_callsite(idx, callsite); if self.dereferenceable_bytes != 0 { - LLVMRustAddDereferenceableCallSiteAttr( - callsite, - idx.as_uint(), - self.dereferenceable_bytes); + LLVMRustAddDereferenceableCallSiteAttr(callsite, + idx.as_uint(), + self.dereferenceable_bytes); } } } } -pub fn AddFunctionAttrStringValue( - llfn: ValueRef, - idx: AttributePlace, - attr: &'static str, - value: &'static str -) { +pub fn AddFunctionAttrStringValue(llfn: ValueRef, + idx: AttributePlace, + attr: &'static str, + value: &'static str) { unsafe { - LLVMRustAddFunctionAttrStringValue( - llfn, - idx.as_uint(), - attr.as_ptr() as *const _, - value.as_ptr() as *const _) + LLVMRustAddFunctionAttrStringValue(llfn, + idx.as_uint(), + attr.as_ptr() as *const _, + value.as_ptr() as *const _) } } @@ -233,44 +228,30 @@ pub fn set_thread_local(global: ValueRef, is_thread_local: bool) { impl Attribute { pub fn apply_llfn(&self, idx: AttributePlace, llfn: ValueRef) { - unsafe { - LLVMRustAddFunctionAttribute( - llfn, idx.as_uint(), self.bits()) - } + unsafe { LLVMRustAddFunctionAttribute(llfn, idx.as_uint(), self.bits()) } } pub fn apply_callsite(&self, idx: AttributePlace, callsite: ValueRef) { - unsafe { - LLVMRustAddCallSiteAttribute( - callsite, idx.as_uint(), self.bits()) - } + unsafe { LLVMRustAddCallSiteAttribute(callsite, idx.as_uint(), self.bits()) } } pub fn unapply_llfn(&self, idx: AttributePlace, llfn: ValueRef) { - unsafe { - LLVMRustRemoveFunctionAttributes( - llfn, idx.as_uint(), self.bits()) - } + unsafe { LLVMRustRemoveFunctionAttributes(llfn, idx.as_uint(), self.bits()) } } - pub fn toggle_llfn(&self, - idx: AttributePlace, - llfn: ValueRef, - set: bool) - { + pub fn toggle_llfn(&self, idx: AttributePlace, llfn: ValueRef, set: bool) { if set { self.apply_llfn(idx, llfn); } else { self.unapply_llfn(idx, llfn); } } - } -/* Memory-managed interface to target data. */ +// Memory-managed interface to target data. pub struct TargetData { - pub lltd: TargetDataRef + pub lltd: TargetDataRef, } impl Drop for TargetData { @@ -283,12 +264,10 @@ impl Drop for TargetData { pub fn mk_target_data(string_rep: &str) -> TargetData { let string_rep = CString::new(string_rep).unwrap(); - TargetData { - lltd: unsafe { LLVMCreateTargetData(string_rep.as_ptr()) } - } + TargetData { lltd: unsafe { LLVMCreateTargetData(string_rep.as_ptr()) } } } -/* Memory-managed interface to object files. */ +// Memory-managed interface to object files. pub struct ObjectFile { pub llof: ObjectFileRef, @@ -301,12 +280,10 @@ impl ObjectFile { let llof = LLVMCreateObjectFile(llmb); if llof as isize == 0 { // LLVMCreateObjectFile took ownership of llmb - return None + return None; } - Some(ObjectFile { - llof: llof, - }) + Some(ObjectFile { llof: llof }) } } } @@ -319,10 +296,10 @@ impl Drop for ObjectFile { } } -/* Memory-managed interface to section iterators. */ +// Memory-managed interface to section iterators. pub struct SectionIter { - pub llsi: SectionIteratorRef + pub llsi: SectionIteratorRef, } impl Drop for SectionIter { @@ -334,11 +311,7 @@ impl Drop for SectionIter { } pub fn mk_section_iter(llof: ObjectFileRef) -> SectionIter { - unsafe { - SectionIter { - llsi: LLVMGetSections(llof) - } - } + unsafe { SectionIter { llsi: LLVMGetSections(llof) } } } /// Safe wrapper around `LLVMGetParam`, because segfaults are no fun. @@ -361,15 +334,16 @@ pub fn get_params(llfn: ValueRef) -> Vec { } } -pub fn build_string(f: F) -> Option where F: FnOnce(RustStringRef){ +pub fn build_string(f: F) -> Option + where F: FnOnce(RustStringRef) +{ let mut buf = RefCell::new(Vec::new()); f(&mut buf as RustStringRepr as RustStringRef); String::from_utf8(buf.into_inner()).ok() } pub unsafe fn twine_to_string(tr: TwineRef) -> String { - build_string(|s| LLVMRustWriteTwineToString(tr, s)) - .expect("got a non-UTF8 Twine from LLVM") + build_string(|s| LLVMRustWriteTwineToString(tr, s)).expect("got a non-UTF8 Twine from LLVM") } pub unsafe fn debug_loc_to_string(c: ContextRef, tr: DebugLocRef) -> String { @@ -434,6 +408,10 @@ pub fn initialize_available_targets() { LLVMInitializeSystemZTargetMC, LLVMInitializeSystemZAsmPrinter, LLVMInitializeSystemZAsmParser); + init_target!(llvm_component = "jsbackend", + LLVMInitializeJSBackendTargetInfo, + LLVMInitializeJSBackendTarget, + LLVMInitializeJSBackendTargetMC); } pub fn last_error() -> Option { @@ -458,9 +436,7 @@ impl OperandBundleDef { pub fn new(name: &str, vals: &[ValueRef]) -> OperandBundleDef { let name = CString::new(name).unwrap(); let def = unsafe { - LLVMRustBuildOperandBundleDef(name.as_ptr(), - vals.as_ptr(), - vals.len() as c_uint) + LLVMRustBuildOperandBundleDef(name.as_ptr(), vals.as_ptr(), vals.len() as c_uint) }; OperandBundleDef { inner: def } } diff --git a/src/librustc_macro/lib.rs b/src/librustc_macro/lib.rs deleted file mode 100644 index c2a2cc2ecd..0000000000 --- a/src/librustc_macro/lib.rs +++ /dev/null @@ -1,169 +0,0 @@ -// Copyright 2016 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution and at -// http://rust-lang.org/COPYRIGHT. -// -// Licensed under the Apache License, Version 2.0 or the MIT license -// , at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - -//! A support library for macro authors when defining new macros. -//! -//! This library, provided by the standard distribution, provides the types -//! consumed in the interfaces of procedurally defined macro definitions. -//! Currently the primary use of this crate is to provide the ability to define -//! new custom derive modes through `#[rustc_macro_derive]`. -//! -//! Added recently as part of [RFC 1681] this crate is currently *unstable* and -//! requires the `#![feature(rustc_macro_lib)]` directive to use. Eventually, -//! though, it is intended for this crate to become stable to use (perhaps under -//! a different name). -//! -//! [RFC 1681]: https://github.com/rust-lang/rfcs/blob/master/text/1681-macros-1.1.md -//! -//! Note that this crate is intentionally very bare-bones currently. The main -//! type, `TokenStream`, only supports `fmt::Display` and `FromStr` -//! implementations, indicating that it can only go to and come from a string. -//! This functionality is intended to be expanded over time as more surface -//! area for macro authors is stabilized. - -#![crate_name = "rustc_macro"] -#![unstable(feature = "rustc_macro_lib", issue = "27812")] -#![crate_type = "rlib"] -#![crate_type = "dylib"] -#![cfg_attr(not(stage0), deny(warnings))] -#![deny(missing_docs)] - -#![feature(rustc_private)] -#![feature(staged_api)] -#![feature(lang_items)] - -extern crate syntax; - -use std::fmt; -use std::str::FromStr; - -use syntax::ast; -use syntax::parse; -use syntax::ptr::P; - -/// The main type provided by this crate, representing an abstract stream of -/// tokens. -/// -/// This is both the input and output of `#[rustc_macro_derive]` definitions. -/// Currently it's required to be a list of valid Rust items, but this -/// restriction may be lifted in the future. -/// -/// The API of this type is intentionally bare-bones, but it'll be expanded over -/// time! -pub struct TokenStream { - inner: Vec>, -} - -/// Error returned from `TokenStream::from_str`. -#[derive(Debug)] -pub struct LexError { - _inner: (), -} - -/// Permanently unstable internal implementation details of this crate. This -/// should not be used. -/// -/// These methods are used by the rest of the compiler to generate instances of -/// `TokenStream` to hand to macro definitions, as well as consume the output. -/// -/// Note that this module is also intentionally separate from the rest of the -/// crate. This allows the `#[unstable]` directive below to naturally apply to -/// all of the contents. -#[unstable(feature = "rustc_macro_internals", issue = "27812")] -#[doc(hidden)] -pub mod __internal { - use std::cell::Cell; - - use syntax::ast; - use syntax::ptr::P; - use syntax::parse::ParseSess; - use super::TokenStream; - - pub fn new_token_stream(item: P) -> TokenStream { - TokenStream { inner: vec![item] } - } - - pub fn token_stream_items(stream: TokenStream) -> Vec> { - stream.inner - } - - pub trait Registry { - fn register_custom_derive(&mut self, - trait_name: &str, - expand: fn(TokenStream) -> TokenStream); - } - - // Emulate scoped_thread_local!() here essentially - thread_local! { - static CURRENT_SESS: Cell<*const ParseSess> = Cell::new(0 as *const _); - } - - pub fn set_parse_sess(sess: &ParseSess, f: F) -> R - where F: FnOnce() -> R - { - struct Reset { prev: *const ParseSess } - - impl Drop for Reset { - fn drop(&mut self) { - CURRENT_SESS.with(|p| p.set(self.prev)); - } - } - - CURRENT_SESS.with(|p| { - let _reset = Reset { prev: p.get() }; - p.set(sess); - f() - }) - } - - pub fn with_parse_sess(f: F) -> R - where F: FnOnce(&ParseSess) -> R - { - let p = CURRENT_SESS.with(|p| p.get()); - assert!(!p.is_null()); - f(unsafe { &*p }) - } -} - -impl FromStr for TokenStream { - type Err = LexError; - - fn from_str(src: &str) -> Result { - __internal::with_parse_sess(|sess| { - let src = src.to_string(); - let cfg = Vec::new(); - let name = "rustc-macro source code".to_string(); - let mut parser = parse::new_parser_from_source_str(sess, cfg, name, - src); - let mut ret = TokenStream { inner: Vec::new() }; - loop { - match parser.parse_item() { - Ok(Some(item)) => ret.inner.push(item), - Ok(None) => return Ok(ret), - Err(mut err) => { - err.cancel(); - return Err(LexError { _inner: () }) - } - } - } - }) - } -} - -impl fmt::Display for TokenStream { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - for item in self.inner.iter() { - let item = syntax::print::pprust::item_to_string(item); - try!(f.write_str(&item)); - try!(f.write_str("\n")); - } - Ok(()) - } -} diff --git a/src/librustc_metadata/Cargo.toml b/src/librustc_metadata/Cargo.toml index 680d55955b..6f7f03ca21 100644 --- a/src/librustc_metadata/Cargo.toml +++ b/src/librustc_metadata/Cargo.toml @@ -11,13 +11,13 @@ crate-type = ["dylib"] [dependencies] flate = { path = "../libflate" } log = { path = "../liblog" } +proc_macro = { path = "../libproc_macro" } rustc = { path = "../librustc" } rustc_back = { path = "../librustc_back" } rustc_const_math = { path = "../librustc_const_math" } rustc_data_structures = { path = "../librustc_data_structures" } rustc_errors = { path = "../librustc_errors" } rustc_llvm = { path = "../librustc_llvm" } -rustc_macro = { path = "../librustc_macro" } serialize = { path = "../libserialize" } syntax = { path = "../libsyntax" } syntax_ext = { path = "../libsyntax_ext" } diff --git a/src/librustc_metadata/astencode.rs b/src/librustc_metadata/astencode.rs index c9dbedacbc..e009955b92 100644 --- a/src/librustc_metadata/astencode.rs +++ b/src/librustc_metadata/astencode.rs @@ -30,7 +30,7 @@ use rustc_serialize::Encodable; pub struct Ast<'tcx> { id_range: IdRange, item: Lazy, - side_tables: LazySeq<(ast::NodeId, TableEntry<'tcx>)> + side_tables: LazySeq<(ast::NodeId, TableEntry<'tcx>)>, } #[derive(RustcEncodable, RustcDecodable)] @@ -38,8 +38,8 @@ enum TableEntry<'tcx> { Def(Def), NodeType(Ty<'tcx>), ItemSubsts(ty::ItemSubsts<'tcx>), - Adjustment(ty::adjustment::AutoAdjustment<'tcx>), - ConstQualif(ConstQualif) + Adjustment(ty::adjustment::Adjustment<'tcx>), + ConstQualif(ConstQualif), } impl<'a, 'tcx> EncodeContext<'a, 'tcx> { @@ -48,7 +48,7 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> { match ii { InlinedItemRef::Item(_, i) => id_visitor.visit_item(i), InlinedItemRef::TraitItem(_, ti) => id_visitor.visit_trait_item(ti), - InlinedItemRef::ImplItem(_, ii) => id_visitor.visit_impl_item(ii) + InlinedItemRef::ImplItem(_, ii) => id_visitor.visit_impl_item(ii), } let ii_pos = self.position(); @@ -58,12 +58,12 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> { let tables_count = { let mut visitor = SideTableEncodingIdVisitor { ecx: self, - count: 0 + count: 0, }; match ii { InlinedItemRef::Item(_, i) => visitor.visit_item(i), InlinedItemRef::TraitItem(_, ti) => visitor.visit_trait_item(ti), - InlinedItemRef::ImplItem(_, ii) => visitor.visit_impl_item(ii) + InlinedItemRef::ImplItem(_, ii) => visitor.visit_impl_item(ii), } visitor.count }; @@ -71,14 +71,14 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> { self.lazy(&Ast { id_range: id_visitor.result(), item: Lazy::with_position(ii_pos), - side_tables: LazySeq::with_position_and_length(tables_pos, tables_count) + side_tables: LazySeq::with_position_and_length(tables_pos, tables_count), }) } } -struct SideTableEncodingIdVisitor<'a, 'b:'a, 'tcx:'b> { +struct SideTableEncodingIdVisitor<'a, 'b: 'a, 'tcx: 'b> { ecx: &'a mut EncodeContext<'b, 'tcx>, - count: usize + count: usize, } impl<'a, 'b, 'tcx, 'v> Visitor<'v> for SideTableEncodingIdVisitor<'a, 'b, 'tcx> { @@ -94,9 +94,9 @@ impl<'a, 'b, 'tcx, 'v> Visitor<'v> for SideTableEncodingIdVisitor<'a, 'b, 'tcx> }; encode(tcx.expect_def_or_none(id).map(TableEntry::Def)); - encode(tcx.node_types().get(&id).cloned().map(TableEntry::NodeType)); - encode(tcx.tables.borrow().item_substs.get(&id).cloned().map(TableEntry::ItemSubsts)); - encode(tcx.tables.borrow().adjustments.get(&id).cloned().map(TableEntry::Adjustment)); + encode(tcx.tables().node_types.get(&id).cloned().map(TableEntry::NodeType)); + encode(tcx.tables().item_substs.get(&id).cloned().map(TableEntry::ItemSubsts)); + encode(tcx.tables().adjustments.get(&id).cloned().map(TableEntry::Adjustment)); encode(tcx.const_qualif_map.borrow().get(&id).cloned().map(TableEntry::ConstQualif)); } } @@ -114,10 +114,11 @@ pub fn decode_inlined_item<'a, 'tcx>(cdata: &CrateMetadata, let cnt = ast.id_range.max.as_usize() - ast.id_range.min.as_usize(); let start = tcx.sess.reserve_node_ids(cnt); - let id_ranges = [ast.id_range, IdRange { - min: start, - max: ast::NodeId::new(start.as_usize() + cnt) - }]; + let id_ranges = [ast.id_range, + IdRange { + min: start, + max: ast::NodeId::new(start.as_usize() + cnt), + }]; let ii = ast.item.decode((cdata, tcx, id_ranges)); let ii = ast_map::map_decoded_item(&tcx.map, @@ -129,7 +130,7 @@ pub fn decode_inlined_item<'a, 'tcx>(cdata: &CrateMetadata, let item_node_id = match ii { &InlinedItem::Item(_, ref i) => i.id, &InlinedItem::TraitItem(_, ref ti) => ti.id, - &InlinedItem::ImplItem(_, ref ii) => ii.id + &InlinedItem::ImplItem(_, ref ii) => ii.id, }; let inlined_did = tcx.map.local_def_id(item_node_id); tcx.register_item_type(inlined_did, tcx.lookup_item_type(orig_did)); diff --git a/src/librustc_metadata/creader.rs b/src/librustc_metadata/creader.rs index 2e03b7868a..e72ac84199 100644 --- a/src/librustc_metadata/creader.rs +++ b/src/librustc_metadata/creader.rs @@ -11,20 +11,19 @@ //! Validates all used crates and extern libraries and loads their metadata use cstore::{self, CStore, CrateSource, MetadataBlob}; -use loader::{self, CratePaths}; -use macro_import; +use locator::{self, CratePaths}; use schema::CrateRoot; use rustc::hir::def_id::{CrateNum, DefIndex}; use rustc::hir::svh::Svh; -use rustc::middle::cstore::LoadedMacro; +use rustc::middle::cstore::LoadedMacros; use rustc::session::{config, Session}; -use rustc::session::config::PanicStrategy; +use rustc_back::PanicStrategy; use rustc::session::search_paths::PathKind; use rustc::middle; use rustc::middle::cstore::{CrateStore, validate_crate_name, ExternCrate}; use rustc::util::nodemap::{FnvHashMap, FnvHashSet}; -use rustc::hir::map as hir_map; +use rustc::hir::map::Definitions; use std::cell::{RefCell, Cell}; use std::ops::Deref; @@ -36,23 +35,23 @@ use syntax::ast; use syntax::abi::Abi; use syntax::parse; use syntax::attr; -use syntax::parse::token::InternedString; +use syntax::ext::base::SyntaxExtension; +use syntax::parse::token::{InternedString, intern}; use syntax_pos::{self, Span, mk_sp}; use log; -pub struct CrateLoader<'a> { - pub sess: &'a Session, - pub creader: CrateReader<'a>, - cstore: &'a CStore, +pub struct Library { + pub dylib: Option<(PathBuf, PathKind)>, + pub rlib: Option<(PathBuf, PathKind)>, + pub metadata: MetadataBlob, } -pub struct CrateReader<'a> { - sess: &'a Session, +pub struct CrateLoader<'a> { + pub sess: &'a Session, cstore: &'a CStore, next_crate_num: CrateNum, foreign_item_map: FnvHashMap>, local_crate_name: String, - local_crate_config: ast::CrateConfig, } fn dump_crates(cstore: &CStore) { @@ -120,16 +119,11 @@ struct ExtensionCrate { metadata: PMDSource, dylib: Option, target_only: bool, - - ident: String, - name: String, - span: Span, - should_link: bool, } enum PMDSource { Registered(Rc), - Owned(loader::Library), + Owned(Library), } impl Deref for PMDSource { @@ -145,33 +139,17 @@ impl Deref for PMDSource { enum LoadResult { Previous(CrateNum), - Loaded(loader::Library), + Loaded(Library), } -pub struct Macros { - pub macro_rules: Vec, - - /// An array of pairs where the first element is the name of the custom - /// derive (e.g. the trait being derived) and the second element is the - /// index of the definition. - pub custom_derive_registrar: Option, - pub svh: Svh, - pub dylib: Option, -} - -impl<'a> CrateReader<'a> { - pub fn new(sess: &'a Session, - cstore: &'a CStore, - local_crate_name: &str, - local_crate_config: ast::CrateConfig) - -> CrateReader<'a> { - CrateReader { +impl<'a> CrateLoader<'a> { + pub fn new(sess: &'a Session, cstore: &'a CStore, local_crate_name: &str) -> Self { + CrateLoader { sess: sess, cstore: cstore, next_crate_num: cstore.next_crate_num(), foreign_item_map: FnvHashMap(), local_crate_name: local_crate_name.to_owned(), - local_crate_config: local_crate_config, } } @@ -281,7 +259,7 @@ impl<'a> CrateReader<'a> { ident: &str, name: &str, span: Span, - lib: loader::Library, + lib: Library, explicitly_linked: bool) -> (CrateNum, Rc, cstore::CrateSource) { @@ -306,12 +284,12 @@ impl<'a> CrateReader<'a> { // Maintain a reference to the top most crate. let root = if root.is_some() { root } else { &crate_paths }; - let loader::Library { dylib, rlib, metadata } = lib; + let Library { dylib, rlib, metadata } = lib; let cnum_map = self.resolve_crate_deps(root, &crate_root, &metadata, cnum, span); if crate_root.macro_derive_registrar.is_some() { - self.sess.span_err(span, "crates of the `rustc-macro` crate type \ + self.sess.span_err(span, "crates of the `proc-macro` crate type \ cannot be linked at runtime"); } @@ -352,7 +330,7 @@ impl<'a> CrateReader<'a> { Some(cnum) => LoadResult::Previous(cnum), None => { info!("falling back to a load"); - let mut load_ctxt = loader::Context { + let mut locate_ctxt = locator::Context { sess: self.sess, span: span, ident: ident, @@ -362,15 +340,15 @@ impl<'a> CrateReader<'a> { target: &self.sess.target.target, triple: &self.sess.opts.target_triple, root: root, - rejected_via_hash: vec!(), - rejected_via_triple: vec!(), - rejected_via_kind: vec!(), - rejected_via_version: vec!(), + rejected_via_hash: vec![], + rejected_via_triple: vec![], + rejected_via_kind: vec![], + rejected_via_version: vec![], should_match_name: true, }; - match self.load(&mut load_ctxt) { + match self.load(&mut locate_ctxt) { Some(result) => result, - None => load_ctxt.report_load_errs(), + None => locate_ctxt.report_errs(), } } }; @@ -390,8 +368,8 @@ impl<'a> CrateReader<'a> { } } - fn load(&mut self, loader: &mut loader::Context) -> Option { - let library = match loader.maybe_load_library_crate() { + fn load(&mut self, locate_ctxt: &mut locator::Context) -> Option { + let library = match locate_ctxt.maybe_load_library_crate() { Some(lib) => lib, None => return None, }; @@ -405,11 +383,11 @@ impl<'a> CrateReader<'a> { // don't want to match a host crate against an equivalent target one // already loaded. let root = library.metadata.get_root(); - if loader.triple == self.sess.opts.target_triple { + if locate_ctxt.triple == self.sess.opts.target_triple { let mut result = LoadResult::Loaded(library); self.cstore.iter_crate_data(|cnum, data| { if data.name() == root.name && root.hash == data.hash() { - assert!(loader.hash.is_none()); + assert!(locate_ctxt.hash.is_none()); info!("load success, going to previous cnum: {}", cnum); result = LoadResult::Previous(cnum); } @@ -490,11 +468,10 @@ impl<'a> CrateReader<'a> { info.id, info.name, info.ident, info.should_link); let target_triple = &self.sess.opts.target_triple[..]; let is_cross = target_triple != config::host_triple(); - let mut should_link = info.should_link && !is_cross; let mut target_only = false; let ident = info.ident.clone(); let name = info.name.clone(); - let mut load_ctxt = loader::Context { + let mut locate_ctxt = locator::Context { sess: self.sess, span: span, ident: &ident[..], @@ -504,30 +481,29 @@ impl<'a> CrateReader<'a> { target: &self.sess.host, triple: config::host_triple(), root: &None, - rejected_via_hash: vec!(), - rejected_via_triple: vec!(), - rejected_via_kind: vec!(), - rejected_via_version: vec!(), + rejected_via_hash: vec![], + rejected_via_triple: vec![], + rejected_via_kind: vec![], + rejected_via_version: vec![], should_match_name: true, }; - let library = self.load(&mut load_ctxt).or_else(|| { + let library = self.load(&mut locate_ctxt).or_else(|| { if !is_cross { return None } // Try loading from target crates. This will abort later if we // try to load a plugin registrar function, target_only = true; - should_link = info.should_link; - load_ctxt.target = &self.sess.target.target; - load_ctxt.triple = target_triple; - load_ctxt.filesearch = self.sess.target_filesearch(PathKind::Crate); + locate_ctxt.target = &self.sess.target.target; + locate_ctxt.triple = target_triple; + locate_ctxt.filesearch = self.sess.target_filesearch(PathKind::Crate); - self.load(&mut load_ctxt) + self.load(&mut locate_ctxt) }); let library = match library { Some(l) => l, - None => load_ctxt.report_load_errs(), + None => locate_ctxt.report_errs(), }; let (dylib, metadata) = match library { @@ -547,30 +523,18 @@ impl<'a> CrateReader<'a> { metadata: metadata, dylib: dylib.map(|p| p.0), target_only: target_only, - name: info.name.to_string(), - ident: info.ident.to_string(), - span: span, - should_link: should_link, } } - pub fn read_macros(&mut self, item: &ast::Item) -> Macros { - let ci = self.extract_crate_info(item).unwrap(); - let ekrate = self.read_extension_crate(item.span, &ci); - + fn read_macros(&mut self, item: &ast::Item, ekrate: &ExtensionCrate) -> LoadedMacros { let root = ekrate.metadata.get_root(); let source_name = format!("<{} macros>", item.ident); - let mut ret = Macros { - macro_rules: Vec::new(), - custom_derive_registrar: None, - svh: root.hash, - dylib: None, - }; + let mut macro_rules = Vec::new(); + for def in root.macro_defs.decode(&*ekrate.metadata) { // NB: Don't use parse::parse_tts_from_source_str because it parses with // quote_depth > 0. let mut p = parse::new_parser_from_source_str(&self.sess.parse_sess, - self.local_crate_config.clone(), source_name.clone(), def.body); let lo = p.span.lo; @@ -582,61 +546,97 @@ impl<'a> CrateReader<'a> { unreachable!(); } }; - let local_span = mk_sp(lo, p.last_span.hi); + let local_span = mk_sp(lo, p.prev_span.hi); // Mark the attrs as used for attr in &def.attrs { attr::mark_used(attr); } - ret.macro_rules.push(ast::MacroDef { + macro_rules.push(ast::MacroDef { ident: ast::Ident::with_empty_ctxt(def.name), - attrs: def.attrs, id: ast::DUMMY_NODE_ID, span: local_span, imported_from: Some(item.ident), - // overridden in plugin/load.rs - export: false, - use_locally: false, - allow_internal_unstable: false, - + allow_internal_unstable: attr::contains_name(&def.attrs, "allow_internal_unstable"), + attrs: def.attrs, body: body, }); self.sess.imported_macro_spans.borrow_mut() .insert(local_span, (def.name.as_str().to_string(), def.span)); } - match root.macro_derive_registrar { - Some(id) => ret.custom_derive_registrar = Some(id), - - // If this crate is not a rustc-macro crate then we might be able to - // register it with the local crate store to prevent loading the - // metadata twice. - // - // If it's a rustc-macro crate, though, then we definitely don't - // want to register it with the local crate store as we're just - // going to use it as we would a plugin. - None => { - ekrate.register(self); - return ret + if let Some(id) = root.macro_derive_registrar { + let dylib = match ekrate.dylib.clone() { + Some(dylib) => dylib, + None => span_bug!(item.span, "proc-macro crate not dylib"), + }; + if ekrate.target_only { + let message = format!("proc-macro crate is not available for \ + triple `{}` (only found {})", + config::host_triple(), + self.sess.opts.target_triple); + self.sess.span_fatal(item.span, &message); } - } - self.cstore.add_used_for_derive_macros(item); - ret.dylib = ekrate.dylib.clone(); - if ret.dylib.is_none() { - span_bug!(item.span, "rustc-macro crate not dylib"); + // custom derive crates currently should not have any macro_rules! + // exported macros, enforced elsewhere + assert_eq!(macro_rules.len(), 0); + LoadedMacros::ProcMacros(self.load_derive_macros(item, id, root.hash, dylib)) + } else { + LoadedMacros::MacroRules(macro_rules) } + } - if ekrate.target_only { - let message = format!("rustc-macro crate is not available for \ - triple `{}` (only found {})", - config::host_triple(), - self.sess.opts.target_triple); - self.sess.span_fatal(item.span, &message); + /// Load custom derive macros. + /// + /// Note that this is intentionally similar to how we load plugins today, + /// but also intentionally separate. Plugins are likely always going to be + /// implemented as dynamic libraries, but we have a possible future where + /// custom derive (and other macro-1.1 style features) are implemented via + /// executables and custom IPC. + fn load_derive_macros(&mut self, item: &ast::Item, index: DefIndex, svh: Svh, path: PathBuf) + -> Vec<(ast::Name, SyntaxExtension)> { + use std::{env, mem}; + use proc_macro::TokenStream; + use proc_macro::__internal::Registry; + use rustc_back::dynamic_lib::DynamicLibrary; + use syntax_ext::deriving::custom::CustomDerive; + + // Make sure the path contains a / or the linker will search for it. + let path = env::current_dir().unwrap().join(path); + let lib = match DynamicLibrary::open(Some(&path)) { + Ok(lib) => lib, + Err(err) => self.sess.span_fatal(item.span, &err), + }; + + let sym = self.sess.generate_derive_registrar_symbol(&svh, index); + let registrar = unsafe { + let sym = match lib.symbol(&sym) { + Ok(f) => f, + Err(err) => self.sess.span_fatal(item.span, &err), + }; + mem::transmute::<*mut u8, fn(&mut Registry)>(sym) + }; + + struct MyRegistrar(Vec<(ast::Name, SyntaxExtension)>); + + impl Registry for MyRegistrar { + fn register_custom_derive(&mut self, + trait_name: &str, + expand: fn(TokenStream) -> TokenStream) { + let derive = SyntaxExtension::CustomDerive(Box::new(CustomDerive::new(expand))); + self.0.push((intern(trait_name), derive)); + } } - return ret + let mut my_registrar = MyRegistrar(Vec::new()); + registrar(&mut my_registrar); + + // Intentionally leak the dynamic library. We can't ever unload it + // since the library can make things that will live arbitrarily long. + mem::forget(lib); + my_registrar.0 } /// Look for a plugin registrar. Returns library path, crate @@ -710,7 +710,7 @@ impl<'a> CrateReader<'a> { // The logic for finding the panic runtime here is pretty much the same // as the allocator case with the only addition that the panic strategy // compilation mode also comes into play. - let desired_strategy = self.sess.opts.cg.panic.clone(); + let desired_strategy = self.sess.panic_strategy(); let mut runtime_found = false; let mut needs_panic_runtime = attr::contains_name(&krate.attrs, "needs_panic_runtime"); @@ -804,7 +804,7 @@ impl<'a> CrateReader<'a> { match *ct { config::CrateTypeExecutable => need_exe_alloc = true, config::CrateTypeDylib | - config::CrateTypeRustcMacro | + config::CrateTypeProcMacro | config::CrateTypeCdylib | config::CrateTypeStaticlib => need_lib_alloc = true, config::CrateTypeRlib => {} @@ -889,43 +889,13 @@ impl<'a> CrateReader<'a> { } } -impl ExtensionCrate { - fn register(self, creader: &mut CrateReader) { - if !self.should_link { - return - } - - let library = match self.metadata { - PMDSource::Owned(lib) => lib, - PMDSource::Registered(_) => return, - }; - - // Register crate now to avoid double-reading metadata - creader.register_crate(&None, - &self.ident, - &self.name, - self.span, - library, - true); - } -} - impl<'a> CrateLoader<'a> { - pub fn new(sess: &'a Session, cstore: &'a CStore, krate: &ast::Crate, crate_name: &str) - -> Self { - let loader = CrateLoader { - sess: sess, - cstore: cstore, - creader: CrateReader::new(sess, cstore, crate_name, krate.config.clone()), - }; - + pub fn preprocess(&mut self, krate: &ast::Crate) { for attr in krate.attrs.iter().filter(|m| m.name() == "link_args") { if let Some(ref linkarg) = attr.value_str() { - loader.cstore.add_used_link_args(&linkarg); + self.cstore.add_used_link_args(&linkarg); } } - - loader } fn process_foreign_mod(&mut self, i: &ast::Item, fm: &ast::ForeignMod) { @@ -982,7 +952,7 @@ impl<'a> CrateLoader<'a> { Some(name) => name, None => continue, }; - let list = self.creader.foreign_item_map.entry(lib_name.to_string()) + let list = self.foreign_item_map.entry(lib_name.to_string()) .or_insert(Vec::new()); list.extend(fm.items.iter().map(|it| it.id)); } @@ -991,8 +961,8 @@ impl<'a> CrateLoader<'a> { impl<'a> middle::cstore::CrateLoader for CrateLoader<'a> { fn postprocess(&mut self, krate: &ast::Crate) { - self.creader.inject_allocator_crate(); - self.creader.inject_panic_runtime(krate); + self.inject_allocator_crate(); + self.inject_panic_runtime(krate); if log_enabled!(log::INFO) { dump_crates(&self.cstore); @@ -1001,50 +971,59 @@ impl<'a> middle::cstore::CrateLoader for CrateLoader<'a> { for &(ref name, kind) in &self.sess.opts.libs { register_native_lib(self.sess, self.cstore, None, name.clone(), kind); } - self.creader.register_statically_included_foreign_items(); + self.register_statically_included_foreign_items(); } - fn process_item(&mut self, item: &ast::Item, definitions: &hir_map::Definitions) { + fn process_item(&mut self, item: &ast::Item, definitions: &Definitions, load_macros: bool) + -> Option { match item.node { ast::ItemKind::ExternCrate(_) => {} - ast::ItemKind::ForeignMod(ref fm) => return self.process_foreign_mod(item, fm), - _ => return, + ast::ItemKind::ForeignMod(ref fm) => { + self.process_foreign_mod(item, fm); + return None; + } + _ => return None, } - // If this `extern crate` item has `#[macro_use]` then we can safely skip it. - // These annotations were processed during macro expansion and are already loaded - // (if necessary) into our crate store. - // - // Note that it's important we *don't* fall through below as some `#[macro_use]` - // crates are explicitly not linked (e.g. macro crates) so we want to ensure - // we avoid `resolve_crate` with those. - if attr::contains_name(&item.attrs, "macro_use") { - if self.cstore.was_used_for_derive_macros(item) { - return + let info = self.extract_crate_info(item).unwrap(); + let loaded_macros = if load_macros { + let ekrate = self.read_extension_crate(item.span, &info); + let loaded_macros = self.read_macros(item, &ekrate); + + // If this is a proc-macro crate or `#[no_link]` crate, it is only used at compile time, + // so we return here to avoid registering the crate. + if loaded_macros.is_proc_macros() || !info.should_link { + return Some(loaded_macros); } - } - if let Some(info) = self.creader.extract_crate_info(item) { - if !info.should_link { - return; + // Register crate now to avoid double-reading metadata + if let PMDSource::Owned(lib) = ekrate.metadata { + if ekrate.target_only || config::host_triple() == self.sess.opts.target_triple { + let ExternCrateInfo { ref ident, ref name, .. } = info; + self.register_crate(&None, ident, name, item.span, lib, true); + } } - let (cnum, ..) = self.creader.resolve_crate( - &None, &info.ident, &info.name, None, item.span, PathKind::Crate, true, - ); + Some(loaded_macros) + } else { + if !info.should_link { + return None; + } + None + }; - let def_id = definitions.opt_local_def_id(item.id).unwrap(); - let len = definitions.def_path(def_id.index).data.len(); + let (cnum, ..) = self.resolve_crate( + &None, &info.ident, &info.name, None, item.span, PathKind::Crate, true, + ); - let extern_crate = - ExternCrate { def_id: def_id, span: item.span, direct: true, path_len: len }; - self.creader.update_extern_crate(cnum, extern_crate, &mut FnvHashSet()); + let def_id = definitions.opt_local_def_id(item.id).unwrap(); + let len = definitions.def_path(def_id.index).data.len(); - self.cstore.add_extern_mod_stmt_cnum(info.id, cnum); - } - } + let extern_crate = + ExternCrate { def_id: def_id, span: item.span, direct: true, path_len: len }; + self.update_extern_crate(cnum, extern_crate, &mut FnvHashSet()); + self.cstore.add_extern_mod_stmt_cnum(info.id, cnum); - fn load_macros(&mut self, extern_crate: &ast::Item, allows_macros: bool) -> Vec { - macro_import::load_macros(self, extern_crate, allows_macros) + loaded_macros } } diff --git a/src/librustc_metadata/cstore.rs b/src/librustc_metadata/cstore.rs index 0a1ff70a04..58c70f959b 100644 --- a/src/librustc_metadata/cstore.rs +++ b/src/librustc_metadata/cstore.rs @@ -11,7 +11,7 @@ // The crate store - a central repo for information collected about external // crates and libraries -use loader; +use locator; use schema; use rustc::dep_graph::DepGraph; @@ -19,16 +19,15 @@ use rustc::hir::def_id::{CRATE_DEF_INDEX, CrateNum, DefIndex, DefId}; use rustc::hir::map::DefKey; use rustc::hir::svh::Svh; use rustc::middle::cstore::ExternCrate; -use rustc::session::config::PanicStrategy; +use rustc_back::PanicStrategy; use rustc_data_structures::indexed_vec::IndexVec; -use rustc::util::nodemap::{FnvHashMap, NodeMap, NodeSet, DefIdMap, FnvHashSet}; +use rustc::util::nodemap::{FnvHashMap, NodeMap, NodeSet, DefIdMap}; use std::cell::{RefCell, Cell}; use std::rc::Rc; use std::path::PathBuf; use flate::Bytes; -use syntax::ast::{self, Ident}; -use syntax::attr; +use syntax::{ast, attr}; use syntax_pos; pub use rustc::middle::cstore::{NativeLibraryKind, LinkagePreference}; @@ -43,7 +42,7 @@ pub type CrateNumMap = IndexVec; pub enum MetadataBlob { Inflated(Bytes), - Archive(loader::ArchiveMetadata), + Archive(locator::ArchiveMetadata), } /// Holds information about a syntax_pos::FileMap imported from another crate. @@ -54,7 +53,7 @@ pub struct ImportedFileMap { /// The end of this FileMap within the codemap of its original crate pub original_end_pos: syntax_pos::BytePos, /// The imported FileMap's representation within the local codemap - pub translated_filemap: Rc + pub translated_filemap: Rc, } pub struct CrateMetadata { @@ -105,7 +104,6 @@ pub struct CStore { pub inlined_item_cache: RefCell>>, pub defid_for_inlined_node: RefCell>, pub visible_parent_map: RefCell>, - pub used_for_derive_macro: RefCell>, } impl CStore { @@ -121,7 +119,6 @@ impl CStore { visible_parent_map: RefCell::new(FnvHashMap()), inlined_item_cache: RefCell::new(FnvHashMap()), defid_for_inlined_node: RefCell::new(FnvHashMap()), - used_for_derive_macro: RefCell::new(FnvHashSet()), } } @@ -141,8 +138,8 @@ impl CStore { self.metas.borrow_mut().insert(cnum, data); } - pub fn iter_crate_data(&self, mut i: I) where - I: FnMut(CrateNum, &Rc), + pub fn iter_crate_data(&self, mut i: I) + where I: FnMut(CrateNum, &Rc) { for (&k, v) in self.metas.borrow().iter() { i(k, v); @@ -150,12 +147,14 @@ impl CStore { } /// Like `iter_crate_data`, but passes source paths (if available) as well. - pub fn iter_crate_data_origins(&self, mut i: I) where - I: FnMut(CrateNum, &CrateMetadata, Option), + pub fn iter_crate_data_origins(&self, mut i: I) + where I: FnMut(CrateNum, &CrateMetadata, Option) { for (&k, v) in self.metas.borrow().iter() { let origin = self.opt_used_crate_source(k); - origin.as_ref().map(|cs| { assert!(k == cs.cnum); }); + origin.as_ref().map(|cs| { + assert!(k == cs.cnum); + }); i(k, &v, origin); } } @@ -167,10 +166,12 @@ impl CStore { } } - pub fn opt_used_crate_source(&self, cnum: CrateNum) - -> Option { - self.used_crate_sources.borrow_mut() - .iter().find(|source| source.cnum == cnum).cloned() + pub fn opt_used_crate_source(&self, cnum: CrateNum) -> Option { + self.used_crate_sources + .borrow_mut() + .iter() + .find(|source| source.cnum == cnum) + .cloned() } pub fn reset(&self) { @@ -182,19 +183,17 @@ impl CStore { self.statically_included_foreign_items.borrow_mut().clear(); } - pub fn crate_dependencies_in_rpo(&self, krate: CrateNum) -> Vec - { + pub fn crate_dependencies_in_rpo(&self, krate: CrateNum) -> Vec { let mut ordering = Vec::new(); self.push_dependencies_in_postorder(&mut ordering, krate); ordering.reverse(); ordering } - pub fn push_dependencies_in_postorder(&self, - ordering: &mut Vec, - krate: CrateNum) - { - if ordering.contains(&krate) { return } + pub fn push_dependencies_in_postorder(&self, ordering: &mut Vec, krate: CrateNum) { + if ordering.contains(&krate) { + return; + } let data = self.get_crate_data(krate); for &dep in data.cnum_map.borrow().iter() { @@ -215,7 +214,8 @@ impl CStore { // In order to get this left-to-right dependency ordering, we perform a // topological sort of all crates putting the leaves at the right-most // positions. - pub fn do_get_used_crates(&self, prefer: LinkagePreference) + pub fn do_get_used_crates(&self, + prefer: LinkagePreference) -> Vec<(CrateNum, Option)> { let mut ordering = Vec::new(); for (&num, _) in self.metas.borrow().iter() { @@ -223,12 +223,16 @@ impl CStore { } info!("topological ordering: {:?}", ordering); ordering.reverse(); - let mut libs = self.used_crate_sources.borrow() + let mut libs = self.used_crate_sources + .borrow() .iter() - .map(|src| (src.cnum, match prefer { - LinkagePreference::RequireDynamic => src.dylib.clone().map(|p| p.0), - LinkagePreference::RequireStatic => src.rlib.clone().map(|p| p.0), - })) + .map(|src| { + (src.cnum, + match prefer { + LinkagePreference::RequireDynamic => src.dylib.clone().map(|p| p.0), + LinkagePreference::RequireStatic => src.rlib.clone().map(|p| p.0), + }) + }) .collect::>(); libs.sort_by(|&(a, _), &(b, _)| { let a = ordering.iter().position(|x| *x == a); @@ -243,9 +247,7 @@ impl CStore { self.used_libraries.borrow_mut().push((lib, kind)); } - pub fn get_used_libraries<'a>(&'a self) - -> &'a RefCell> { + pub fn get_used_libraries<'a>(&'a self) -> &'a RefCell> { &self.used_libraries } @@ -255,13 +257,11 @@ impl CStore { } } - pub fn get_used_link_args<'a>(&'a self) -> &'a RefCell > { + pub fn get_used_link_args<'a>(&'a self) -> &'a RefCell> { &self.used_link_args } - pub fn add_extern_mod_stmt_cnum(&self, - emod_id: ast::NodeId, - cnum: CrateNum) { + pub fn add_extern_mod_stmt_cnum(&self, emod_id: ast::NodeId, cnum: CrateNum) { self.extern_mod_crate_map.borrow_mut().insert(emod_id, cnum); } @@ -273,29 +273,26 @@ impl CStore { self.statically_included_foreign_items.borrow().contains(&id) } - pub fn do_extern_mod_stmt_cnum(&self, emod_id: ast::NodeId) -> Option - { + pub fn do_extern_mod_stmt_cnum(&self, emod_id: ast::NodeId) -> Option { self.extern_mod_crate_map.borrow().get(&emod_id).cloned() } - - pub fn was_used_for_derive_macros(&self, i: &ast::Item) -> bool { - self.used_for_derive_macro.borrow().contains(&i.ident) - } - - pub fn add_used_for_derive_macros(&self, i: &ast::Item) { - self.used_for_derive_macro.borrow_mut().insert(i.ident); - } } impl CrateMetadata { - pub fn name(&self) -> &str { &self.root.name } - pub fn hash(&self) -> Svh { self.root.hash } - pub fn disambiguator(&self) -> &str { &self.root.disambiguator } + pub fn name(&self) -> &str { + &self.root.name + } + pub fn hash(&self) -> Svh { + self.root.hash + } + pub fn disambiguator(&self) -> &str { + &self.root.disambiguator + } pub fn is_staged_api(&self) -> bool { - self.get_item_attrs(CRATE_DEF_INDEX).iter().any(|attr| { - attr.name() == "stable" || attr.name() == "unstable" - }) + self.get_item_attrs(CRATE_DEF_INDEX) + .iter() + .any(|attr| attr.name() == "stable" || attr.name() == "unstable") } pub fn is_allocator(&self) -> bool { diff --git a/src/librustc_metadata/csearch.rs b/src/librustc_metadata/cstore_impl.rs similarity index 94% rename from src/librustc_metadata/csearch.rs rename to src/librustc_metadata/cstore_impl.rs index 1f25136ffe..a618c98ff7 100644 --- a/src/librustc_metadata/csearch.rs +++ b/src/librustc_metadata/cstore_impl.rs @@ -10,7 +10,7 @@ use cstore; use encoder; -use loader; +use locator; use schema; use rustc::middle::cstore::{InlinedItem, CrateStore, CrateSource, ExternCrate}; @@ -23,10 +23,9 @@ use rustc::hir::def_id::{CrateNum, DefId, DefIndex, CRATE_DEF_INDEX}; use rustc::dep_graph::DepNode; use rustc::hir::map as hir_map; use rustc::hir::map::DefKey; -use rustc::mir::repr::Mir; -use rustc::mir::mir_map::MirMap; +use rustc::mir::Mir; use rustc::util::nodemap::{NodeSet, DefIdMap}; -use rustc::session::config::PanicStrategy; +use rustc_back::PanicStrategy; use std::path::PathBuf; use syntax::ast; @@ -149,7 +148,7 @@ impl<'tcx> CrateStore<'tcx> for cstore::CStore { self.dep_graph.read(DepNode::MetaData(def_id)); let mut result = vec![]; self.get_crate_data(def_id.krate) - .each_child_of_item(def_id.index, |child| result.push(child.def_id)); + .each_child_of_item(def_id.index, |child| result.push(child.def.def_id())); result } @@ -207,11 +206,6 @@ impl<'tcx> CrateStore<'tcx> for cstore::CStore { self.get_crate_data(impl_did.krate).is_default_impl(impl_did.index) } - fn is_extern_item<'a>(&self, tcx: TyCtxt<'a, 'tcx, 'tcx>, did: DefId) -> bool { - self.dep_graph.read(DepNode::MetaData(did)); - self.get_crate_data(did.krate).is_extern_item(did.index, tcx) - } - fn is_foreign_item(&self, did: DefId) -> bool { self.get_crate_data(did.krate).is_foreign_item(did.index) } @@ -342,18 +336,6 @@ impl<'tcx> CrateStore<'tcx> for cstore::CStore { self.get_crate_data(def.krate).def_path(def.index) } - fn variant_kind(&self, def_id: DefId) -> Option - { - self.dep_graph.read(DepNode::MetaData(def_id)); - self.get_crate_data(def_id.krate).get_variant_kind(def_id.index) - } - - fn struct_ctor_def_id(&self, struct_def_id: DefId) -> Option - { - self.dep_graph.read(DepNode::MetaData(struct_def_id)); - self.get_crate_data(struct_def_id.krate).get_struct_ctor_def_id(struct_def_id.index) - } - fn struct_field_names(&self, def: DefId) -> Vec { self.dep_graph.read(DepNode::MetaData(def)); @@ -479,10 +461,11 @@ impl<'tcx> CrateStore<'tcx> for cstore::CStore { self.defid_for_inlined_node.borrow().get(&node_id).map(|x| *x) } - fn maybe_get_item_mir<'a>(&self, tcx: TyCtxt<'a, 'tcx, 'tcx>, def: DefId) - -> Option> { + fn get_item_mir<'a>(&self, tcx: TyCtxt<'a, 'tcx, 'tcx>, def: DefId) -> Mir<'tcx> { self.dep_graph.read(DepNode::MetaData(def)); - self.get_crate_data(def.krate).maybe_get_item_mir(tcx, def.index) + self.get_crate_data(def.krate).maybe_get_item_mir(tcx, def.index).unwrap_or_else(|| { + bug!("get_item_mir: missing MIR for {}", tcx.item_path_str(def)) + }) } fn is_item_mir_available(&self, def: DefId) -> bool { @@ -509,12 +492,12 @@ impl<'tcx> CrateStore<'tcx> for cstore::CStore { fn metadata_filename(&self) -> &str { - loader::METADATA_FILENAME + locator::METADATA_FILENAME } fn metadata_section_name(&self, target: &Target) -> &str { - loader::meta_section_name(target) + locator::meta_section_name(target) } fn used_crates(&self, prefer: LinkagePreference) -> Vec<(CrateNum, Option)> @@ -535,10 +518,9 @@ impl<'tcx> CrateStore<'tcx> for cstore::CStore { fn encode_metadata<'a>(&self, tcx: TyCtxt<'a, 'tcx, 'tcx>, reexports: &def::ExportMap, link_meta: &LinkMeta, - reachable: &NodeSet, - mir_map: &MirMap<'tcx>) -> Vec + reachable: &NodeSet) -> Vec { - encoder::encode_metadata(tcx, self, reexports, link_meta, reachable, mir_map) + encoder::encode_metadata(tcx, self, reexports, link_meta, reachable) } fn metadata_encoding_version(&self) -> &[u8] @@ -566,7 +548,7 @@ impl<'tcx> CrateStore<'tcx> for cstore::CStore { let mut bfs_queue = &mut VecDeque::new(); let mut add_child = |bfs_queue: &mut VecDeque<_>, child: def::Export, parent: DefId| { - let child = child.def_id; + let child = child.def.def_id(); if self.visibility(child) != ty::Visibility::Public { return; diff --git a/src/librustc_metadata/decoder.rs b/src/librustc_metadata/decoder.rs index ceb6fcb0da..ccd497860d 100644 --- a/src/librustc_metadata/decoder.rs +++ b/src/librustc_metadata/decoder.rs @@ -22,7 +22,7 @@ use rustc::hir; use rustc::hir::intravisit::IdRange; use rustc::middle::cstore::{InlinedItem, LinkagePreference}; -use rustc::hir::def::{self, Def}; +use rustc::hir::def::{self, Def, CtorKind}; use rustc::hir::def_id::{CrateNum, DefId, DefIndex, LOCAL_CRATE}; use rustc::middle::lang_items; use rustc::ty::{self, Ty, TyCtxt}; @@ -30,8 +30,9 @@ use rustc::ty::subst::Substs; use rustc_const_math::ConstInt; -use rustc::mir::repr::Mir; +use rustc::mir::Mir; +use std::borrow::Cow; use std::cell::Ref; use std::io; use std::mem; @@ -55,19 +56,23 @@ pub struct DecodeContext<'a, 'tcx: 'a> { // Cache the last used filemap for translating spans as an optimization. last_filemap_index: usize, - lazy_state: LazyState + lazy_state: LazyState, } /// Abstract over the various ways one can create metadata decoders. pub trait Metadata<'a, 'tcx>: Copy { fn raw_bytes(self) -> &'a [u8]; - fn cdata(self) -> Option<&'a CrateMetadata> { None } - fn tcx(self) -> Option> { None } + fn cdata(self) -> Option<&'a CrateMetadata> { + None + } + fn tcx(self) -> Option> { + None + } fn decoder(self, pos: usize) -> DecodeContext<'a, 'tcx> { let id_range = IdRange { min: NodeId::from_u32(u32::MIN), - max: NodeId::from_u32(u32::MAX) + max: NodeId::from_u32(u32::MAX), }; DecodeContext { opaque: opaque::Decoder::new(self.raw_bytes(), pos), @@ -76,7 +81,7 @@ pub trait Metadata<'a, 'tcx>: Copy { from_id_range: id_range, to_id_range: id_range, last_filemap_index: 0, - lazy_state: LazyState::NoNode + lazy_state: LazyState::NoNode, } } } @@ -91,21 +96,37 @@ impl<'a, 'tcx> Metadata<'a, 'tcx> for &'a MetadataBlob { } impl<'a, 'tcx> Metadata<'a, 'tcx> for &'a CrateMetadata { - fn raw_bytes(self) -> &'a [u8] { self.blob.raw_bytes() } - fn cdata(self) -> Option<&'a CrateMetadata> { Some(self) } + fn raw_bytes(self) -> &'a [u8] { + self.blob.raw_bytes() + } + fn cdata(self) -> Option<&'a CrateMetadata> { + Some(self) + } } impl<'a, 'tcx> Metadata<'a, 'tcx> for (&'a CrateMetadata, TyCtxt<'a, 'tcx, 'tcx>) { - fn raw_bytes(self) -> &'a [u8] { self.0.raw_bytes() } - fn cdata(self) -> Option<&'a CrateMetadata> { Some(self.0) } - fn tcx(self) -> Option> { Some(self.1) } + fn raw_bytes(self) -> &'a [u8] { + self.0.raw_bytes() + } + fn cdata(self) -> Option<&'a CrateMetadata> { + Some(self.0) + } + fn tcx(self) -> Option> { + Some(self.1) + } } // HACK(eddyb) Only used by astencode to customize the from/to IdRange's. impl<'a, 'tcx> Metadata<'a, 'tcx> for (&'a CrateMetadata, TyCtxt<'a, 'tcx, 'tcx>, [IdRange; 2]) { - fn raw_bytes(self) -> &'a [u8] { self.0.raw_bytes() } - fn cdata(self) -> Option<&'a CrateMetadata> { Some(self.0) } - fn tcx(self) -> Option> { Some(self.1) } + fn raw_bytes(self) -> &'a [u8] { + self.0.raw_bytes() + } + fn cdata(self) -> Option<&'a CrateMetadata> { + Some(self.0) + } + fn tcx(self) -> Option> { + Some(self.1) + } fn decoder(self, pos: usize) -> DecodeContext<'a, 'tcx> { let mut dcx = (self.0, self.1).decoder(pos); @@ -124,12 +145,10 @@ impl<'a, 'tcx: 'a, T: Decodable> Lazy { } impl<'a, 'tcx: 'a, T: Decodable> LazySeq { - pub fn decode>(self, meta: M) -> impl Iterator + 'a { + pub fn decode>(self, meta: M) -> impl Iterator + 'a { let mut dcx = meta.decoder(self.position); dcx.lazy_state = LazyState::NodeStart(self.position); - (0..self.len).map(move |_| { - T::decode(&mut dcx).unwrap() - }) + (0..self.len).map(move |_| T::decode(&mut dcx).unwrap()) } } @@ -152,20 +171,15 @@ impl<'a, 'tcx> DecodeContext<'a, 'tcx> { r } - fn read_lazy_distance(&mut self, min_size: usize) - -> Result::Error> { + fn read_lazy_distance(&mut self, min_size: usize) -> Result::Error> { let distance = self.read_usize()?; let position = match self.lazy_state { - LazyState::NoNode => { - bug!("read_lazy_distance: outside of a metadata node") - } + LazyState::NoNode => bug!("read_lazy_distance: outside of a metadata node"), LazyState::NodeStart(start) => { assert!(distance + min_size <= start); start - distance - min_size } - LazyState::Previous(last_min_end) => { - last_min_end + distance - } + LazyState::Previous(last_min_end) => last_min_end + distance, }; self.lazy_state = LazyState::Previous(position + min_size); Ok(position) @@ -202,7 +216,7 @@ impl<'doc, 'tcx> Decoder for DecodeContext<'doc, 'tcx> { read_f64 -> f64; read_f32 -> f32; read_char -> char; - read_str -> String; + read_str -> Cow; } fn error(&mut self, err: &str) -> Self::Error { @@ -238,13 +252,15 @@ impl<'a, 'tcx> SpecializedDecoder for DecodeContext<'a, 'tcx> { // meaningful result if !self.from_id_range.contains(NodeId::from_u32(id)) { bug!("NodeId::decode: {} out of DecodeContext range ({:?} -> {:?})", - id, self.from_id_range, self.to_id_range); + id, + self.from_id_range, + self.to_id_range); } // Use wrapping arithmetic because otherwise it introduces control flow. // Maybe we should just have the control flow? -- aatch Ok(NodeId::from_u32(id.wrapping_sub(self.from_id_range.min.as_u32()) - .wrapping_add(self.to_id_range.min.as_u32()))) + .wrapping_add(self.to_id_range.min.as_u32()))) } } @@ -289,10 +305,9 @@ impl<'a, 'tcx> SpecializedDecoder for DecodeContext<'a, 'tcx> { // originate from the same filemap. let last_filemap = &imported_filemaps[self.last_filemap_index]; - if lo >= last_filemap.original_start_pos && - lo <= last_filemap.original_end_pos && - hi >= last_filemap.original_start_pos && - hi <= last_filemap.original_end_pos { + if lo >= last_filemap.original_start_pos && lo <= last_filemap.original_end_pos && + hi >= last_filemap.original_start_pos && + hi <= last_filemap.original_end_pos { last_filemap } else { let mut a = 0; @@ -312,10 +327,8 @@ impl<'a, 'tcx> SpecializedDecoder for DecodeContext<'a, 'tcx> { } }; - let lo = (lo - filemap.original_start_pos) + - filemap.translated_filemap.start_pos; - let hi = (hi - filemap.original_start_pos) + - filemap.translated_filemap.start_pos; + let lo = (lo - filemap.original_start_pos) + filemap.translated_filemap.start_pos; + let hi = (hi - filemap.original_start_pos) + filemap.translated_filemap.start_pos; Ok(syntax_pos::mk_sp(lo, hi)) } @@ -335,7 +348,7 @@ impl<'a, 'tcx> SpecializedDecoder> for DecodeContext<'a, 'tcx> { assert!(pos >= SHORTHAND_OFFSET); let key = ty::CReaderCacheKey { cnum: self.cdata().cnum, - pos: pos - SHORTHAND_OFFSET + pos: pos - SHORTHAND_OFFSET, }; if let Some(ty) = tcx.rcache.borrow().get(&key).cloned() { return Ok(ty); @@ -356,24 +369,25 @@ impl<'a, 'tcx> SpecializedDecoder> for DecodeContext Ok(ty::GenericPredicates { parent: Decodable::decode(self)?, predicates: (0..self.read_usize()?).map(|_| { - // Handle shorthands first, if we have an usize > 0x80. - if self.opaque.data[self.opaque.position()] & 0x80 != 0 { - let pos = self.read_usize()?; - assert!(pos >= SHORTHAND_OFFSET); - let pos = pos - SHORTHAND_OFFSET; - - self.with_position(pos, ty::Predicate::decode) - } else { - ty::Predicate::decode(self) - } - }).collect::, _>>()? + // Handle shorthands first, if we have an usize > 0x80. + if self.opaque.data[self.opaque.position()] & 0x80 != 0 { + let pos = self.read_usize()?; + assert!(pos >= SHORTHAND_OFFSET); + let pos = pos - SHORTHAND_OFFSET; + + self.with_position(pos, ty::Predicate::decode) + } else { + ty::Predicate::decode(self) + } + }) + .collect::, _>>()?, }) } } impl<'a, 'tcx> SpecializedDecoder<&'tcx Substs<'tcx>> for DecodeContext<'a, 'tcx> { fn specialized_decode(&mut self) -> Result<&'tcx Substs<'tcx>, Self::Error> { - Ok(self.tcx().mk_substs(Decodable::decode(self)?)) + Ok(self.tcx().mk_substs((0..self.read_usize()?).map(|_| Decodable::decode(self)))?) } } @@ -385,7 +399,7 @@ impl<'a, 'tcx> SpecializedDecoder<&'tcx ty::Region> for DecodeContext<'a, 'tcx> impl<'a, 'tcx> SpecializedDecoder<&'tcx ty::Slice>> for DecodeContext<'a, 'tcx> { fn specialized_decode(&mut self) -> Result<&'tcx ty::Slice>, Self::Error> { - Ok(self.tcx().mk_type_list(Decodable::decode(self)?)) + Ok(self.tcx().mk_type_list((0..self.read_usize()?).map(|_| Decodable::decode(self)))?) } } @@ -410,8 +424,7 @@ impl<'a, 'tcx> MetadataBlob { pub fn get_root(&self) -> CrateRoot { let slice = self.raw_bytes(); let offset = METADATA_HEADER.len(); - let pos = (((slice[offset + 0] as u32) << 24) | - ((slice[offset + 1] as u32) << 16) | + let pos = (((slice[offset + 0] as u32) << 24) | ((slice[offset + 1] as u32) << 16) | ((slice[offset + 2] as u32) << 8) | ((slice[offset + 3] as u32) << 0)) as usize; Lazy::with_position(pos).decode(self) @@ -420,9 +433,9 @@ impl<'a, 'tcx> MetadataBlob { /// Go through each item in the metadata and create a map from that /// item's def-key to the item's DefIndex. pub fn load_key_map(&self, index: LazySeq) -> FnvHashMap { - index.iter_enumerated(self.raw_bytes()).map(|(index, item)| { - (item.decode(self).def_key.decode(self), index) - }).collect() + index.iter_enumerated(self.raw_bytes()) + .map(|(index, item)| (item.decode(self).def_key.decode(self), index)) + .collect() } pub fn list_crate_metadata(&self, out: &mut io::Write) -> io::Result<()> { @@ -439,7 +452,7 @@ impl<'a, 'tcx> MetadataBlob { impl<'tcx> EntryKind<'tcx> { fn to_def(&self, did: DefId) -> Option { Some(match *self { - EntryKind::Const => Def::Const(did), + EntryKind::Const => Def::Const(did), EntryKind::AssociatedConst(_) => Def::AssociatedConst(did), EntryKind::ImmStatic | EntryKind::ForeignImmStatic => Def::Static(did, false), @@ -461,9 +474,7 @@ impl<'tcx> EntryKind<'tcx> { EntryKind::Impl(_) | EntryKind::DefaultImpl(_) | EntryKind::Field | - EntryKind::Closure (_) => { - return None - } + EntryKind::Closure(_) => return None, }) } } @@ -475,23 +486,29 @@ impl<'a, 'tcx> CrateMetadata { fn entry(&self, item_id: DefIndex) -> Entry<'tcx> { match self.maybe_entry(item_id) { - None => bug!("entry: id not found: {:?} in crate {:?} with number {}", - item_id, - self.name, - self.cnum), - Some(d) => d.decode(self) + None => { + bug!("entry: id not found: {:?} in crate {:?} with number {}", + item_id, + self.name, + self.cnum) + } + Some(d) => d.decode(self), } } fn local_def_id(&self, index: DefIndex) -> DefId { DefId { krate: self.cnum, - index: index + index: index, } } fn item_name(&self, item: &Entry<'tcx>) -> ast::Name { - item.def_key.decode(self).disambiguated_data.data.get_opt_name() + item.def_key + .decode(self) + .disambiguated_data + .data + .get_opt_name() .expect("no name in item_name") } @@ -501,55 +518,66 @@ impl<'a, 'tcx> CrateMetadata { pub fn get_trait_def(&self, item_id: DefIndex, - tcx: TyCtxt<'a, 'tcx, 'tcx>) -> ty::TraitDef<'tcx> { + tcx: TyCtxt<'a, 'tcx, 'tcx>) + -> ty::TraitDef<'tcx> { let data = match self.entry(item_id).kind { EntryKind::Trait(data) => data.decode(self), - _ => bug!() + _ => bug!(), }; - ty::TraitDef::new(data.unsafety, data.paren_sugar, + ty::TraitDef::new(data.unsafety, + data.paren_sugar, tcx.lookup_generics(self.local_def_id(item_id)), data.trait_ref.decode((self, tcx)), self.def_path(item_id).unwrap().deterministic_hash(tcx)) } - fn get_variant(&self, item: &Entry<'tcx>, index: DefIndex) + fn get_variant(&self, + item: &Entry<'tcx>, + index: DefIndex) -> (ty::VariantDefData<'tcx, 'tcx>, Option) { let data = match item.kind { EntryKind::Variant(data) | EntryKind::Struct(data) | EntryKind::Union(data) => data.decode(self), - _ => bug!() + _ => bug!(), }; - let fields = item.children.decode(self).map(|index| { - let f = self.entry(index); - ty::FieldDefData::new(self.local_def_id(index), - self.item_name(&f), - f.visibility) - }).collect(); + let fields = item.children + .decode(self) + .map(|index| { + let f = self.entry(index); + ty::FieldDefData::new(self.local_def_id(index), self.item_name(&f), f.visibility) + }) + .collect(); (ty::VariantDefData { - did: self.local_def_id(data.struct_ctor.unwrap_or(index)), - name: self.item_name(item), - fields: fields, - disr_val: ConstInt::Infer(data.disr), - kind: data.kind, - }, data.struct_ctor) - } - - pub fn get_adt_def(&self, item_id: DefIndex, tcx: TyCtxt<'a, 'tcx, 'tcx>) + did: self.local_def_id(data.struct_ctor.unwrap_or(index)), + name: self.item_name(item), + fields: fields, + disr_val: ConstInt::Infer(data.disr), + ctor_kind: data.ctor_kind, + }, + data.struct_ctor) + } + + pub fn get_adt_def(&self, + item_id: DefIndex, + tcx: TyCtxt<'a, 'tcx, 'tcx>) -> ty::AdtDefMaster<'tcx> { let item = self.entry(item_id); let did = self.local_def_id(item_id); let mut ctor_index = None; let variants = if let EntryKind::Enum = item.kind { - item.children.decode(self).map(|index| { - let (variant, struct_ctor) = self.get_variant(&self.entry(index), index); - assert_eq!(struct_ctor, None); - variant - }).collect() - } else{ + item.children + .decode(self) + .map(|index| { + let (variant, struct_ctor) = self.get_variant(&self.entry(index), index); + assert_eq!(struct_ctor, None); + variant + }) + .collect() + } else { let (variant, struct_ctor) = self.get_variant(&item, item_id); ctor_index = struct_ctor; vec![variant] @@ -558,7 +586,7 @@ impl<'a, 'tcx> CrateMetadata { EntryKind::Enum => ty::AdtKind::Enum, EntryKind::Struct(_) => ty::AdtKind::Struct, EntryKind::Union(_) => ty::AdtKind::Union, - _ => bug!("get_adt_def called on a non-ADT {:?}", did) + _ => bug!("get_adt_def called on a non-ADT {:?}", did), }; let adt = tcx.intern_adt_def(did, kind, variants); @@ -571,33 +599,41 @@ impl<'a, 'tcx> CrateMetadata { // to support recursive structures for variant in &adt.variants { for field in &variant.fields { - debug!("evaluating the type of {:?}::{:?}", variant.name, field.name); + debug!("evaluating the type of {:?}::{:?}", + variant.name, + field.name); let ty = self.get_type(field.did.index, tcx); field.fulfill_ty(ty); debug!("evaluating the type of {:?}::{:?}: {:?}", - variant.name, field.name, ty); + variant.name, + field.name, + ty); } } adt } - pub fn get_predicates(&self, item_id: DefIndex, tcx: TyCtxt<'a, 'tcx, 'tcx>) + pub fn get_predicates(&self, + item_id: DefIndex, + tcx: TyCtxt<'a, 'tcx, 'tcx>) -> ty::GenericPredicates<'tcx> { self.entry(item_id).predicates.unwrap().decode((self, tcx)) } - pub fn get_super_predicates(&self, item_id: DefIndex, tcx: TyCtxt<'a, 'tcx, 'tcx>) + pub fn get_super_predicates(&self, + item_id: DefIndex, + tcx: TyCtxt<'a, 'tcx, 'tcx>) -> ty::GenericPredicates<'tcx> { match self.entry(item_id).kind { - EntryKind::Trait(data) => { - data.decode(self).super_predicates.decode((self, tcx)) - } - _ => bug!() + EntryKind::Trait(data) => data.decode(self).super_predicates.decode((self, tcx)), + _ => bug!(), } } - pub fn get_generics(&self, item_id: DefIndex, tcx: TyCtxt<'a, 'tcx, 'tcx>) + pub fn get_generics(&self, + item_id: DefIndex, + tcx: TyCtxt<'a, 'tcx, 'tcx>) -> ty::Generics<'tcx> { self.entry(item_id).generics.unwrap().decode((self, tcx)) } @@ -621,7 +657,7 @@ impl<'a, 'tcx> CrateMetadata { fn get_impl_data(&self, id: DefIndex) -> ImplData<'tcx> { match self.entry(id).kind { EntryKind::Impl(data) => data.decode(self), - _ => bug!() + _ => bug!(), } } @@ -633,7 +669,8 @@ impl<'a, 'tcx> CrateMetadata { self.get_impl_data(id).polarity } - pub fn get_custom_coerce_unsized_kind(&self, id: DefIndex) + pub fn get_custom_coerce_unsized_kind(&self, + id: DefIndex) -> Option { self.get_impl_data(id).coerce_unsized_kind } @@ -670,24 +707,53 @@ impl<'a, 'tcx> CrateMetadata { // FIXME(eddyb) Don't encode these in children. EntryKind::ForeignMod => { for child_index in child.children.decode(self) { - callback(def::Export { - def_id: self.local_def_id(child_index), - name: self.item_name(&self.entry(child_index)) - }); + if let Some(def) = self.get_def(child_index) { + callback(def::Export { + def: def, + name: self.item_name(&self.entry(child_index)), + }); + } } continue; } - EntryKind::Impl(_) | EntryKind::DefaultImpl(_) => continue, + EntryKind::Impl(_) | + EntryKind::DefaultImpl(_) => continue, _ => {} } let def_key = child.def_key.decode(self); - if let Some(name) = def_key.disambiguated_data.data.get_opt_name() { + if let (Some(def), Some(name)) = + (self.get_def(child_index), def_key.disambiguated_data.data.get_opt_name()) { callback(def::Export { - def_id: self.local_def_id(child_index), - name: name + def: def, + name: name, }); + // For non-reexport structs and variants add their constructors to children. + // Reexport lists automatically contain constructors when necessary. + match def { + Def::Struct(..) => { + if let Some(ctor_def_id) = self.get_struct_ctor_def_id(child_index) { + let ctor_kind = self.get_ctor_kind(child_index); + let ctor_def = Def::StructCtor(ctor_def_id, ctor_kind); + callback(def::Export { + def: ctor_def, + name: name, + }); + } + } + Def::Variant(def_id) => { + // Braced variants, unlike structs, generate unusable names in + // value namespace, they are reserved for possible future use. + let ctor_kind = self.get_ctor_kind(child_index); + let ctor_def = Def::VariantCtor(def_id, ctor_kind); + callback(def::Export { + def: ctor_def, + name: name, + }); + } + _ => {} + } } } } @@ -699,7 +765,9 @@ impl<'a, 'tcx> CrateMetadata { } } - pub fn maybe_get_item_ast(&self, tcx: TyCtxt<'a, 'tcx, 'tcx>, id: DefIndex) + pub fn maybe_get_item_ast(&self, + tcx: TyCtxt<'a, 'tcx, 'tcx>, + id: DefIndex) -> Option<&'tcx InlinedItem> { debug!("Looking up item: {:?}", id); let item_doc = self.entry(id); @@ -717,12 +785,16 @@ impl<'a, 'tcx> CrateMetadata { self.maybe_entry(id).and_then(|item| item.decode(self).mir).is_some() } - pub fn maybe_get_item_mir(&self, tcx: TyCtxt<'a, 'tcx, 'tcx>, id: DefIndex) + pub fn maybe_get_item_mir(&self, + tcx: TyCtxt<'a, 'tcx, 'tcx>, + id: DefIndex) -> Option> { self.entry(id).mir.map(|mir| mir.decode((self, tcx))) } - pub fn get_impl_or_trait_item(&self, id: DefIndex, tcx: TyCtxt<'a, 'tcx, 'tcx>) + pub fn get_impl_or_trait_item(&self, + id: DefIndex, + tcx: TyCtxt<'a, 'tcx, 'tcx>) -> Option> { let item = self.entry(id); let parent_and_name = || { @@ -749,9 +821,11 @@ impl<'a, 'tcx> CrateMetadata { let ity = item.ty.unwrap().decode((self, tcx)); let fty = match ity.sty { ty::TyFnDef(.., fty) => fty, - _ => bug!( - "the type {:?} of the method {:?} is not a function?", - ity, name) + _ => { + bug!("the type {:?} of the method {:?} is not a function?", + ity, + name) + } }; let data = data.decode(self); @@ -779,7 +853,7 @@ impl<'a, 'tcx> CrateMetadata { container: container.with_def_id(parent), })) } - _ => return None + _ => return None, }) } @@ -787,12 +861,12 @@ impl<'a, 'tcx> CrateMetadata { self.entry(id).variances.decode(self).collect() } - pub fn get_variant_kind(&self, node_id: DefIndex) -> Option { + pub fn get_ctor_kind(&self, node_id: DefIndex) -> CtorKind { match self.entry(node_id).kind { EntryKind::Struct(data) | EntryKind::Union(data) | - EntryKind::Variant(data) => Some(data.decode(self).kind), - _ => None + EntryKind::Variant(data) => data.decode(self).ctor_kind, + _ => CtorKind::Fictive, } } @@ -801,7 +875,7 @@ impl<'a, 'tcx> CrateMetadata { EntryKind::Struct(data) => { data.decode(self).struct_ctor.map(|index| self.local_def_id(index)) } - _ => None + _ => None, } } @@ -818,17 +892,22 @@ impl<'a, 'tcx> CrateMetadata { } pub fn get_struct_field_names(&self, id: DefIndex) -> Vec { - self.entry(id).children.decode(self).map(|index| { - self.item_name(&self.entry(index)) - }).collect() + self.entry(id) + .children + .decode(self) + .map(|index| self.item_name(&self.entry(index))) + .collect() } fn get_attributes(&self, item: &Entry<'tcx>) -> Vec { - item.attributes.decode(self).map(|mut attr| { - // Need new unique IDs: old thread-local IDs won't map to new threads. - attr.node.id = attr::mk_attr_id(); - attr - }).collect() + item.attributes + .decode(self) + .map(|mut attr| { + // Need new unique IDs: old thread-local IDs won't map to new threads. + attr.node.id = attr::mk_attr_id(); + attr + }) + .collect() } // Translate a DefId from the current compilation environment to a DefId @@ -836,7 +915,10 @@ impl<'a, 'tcx> CrateMetadata { fn reverse_translate_def_id(&self, did: DefId) -> Option { for (local, &global) in self.cnum_map.borrow().iter_enumerated() { if global == did.krate { - return Some(DefId { krate: local, index: did.index }); + return Some(DefId { + krate: local, + index: did.index, + }); } } @@ -844,9 +926,11 @@ impl<'a, 'tcx> CrateMetadata { } pub fn get_inherent_implementations_for_type(&self, id: DefIndex) -> Vec { - self.entry(id).inherent_impls.decode(self).map(|index| { - self.local_def_id(index) - }).collect() + self.entry(id) + .inherent_impls + .decode(self) + .map(|index| self.local_def_id(index)) + .collect() } pub fn get_implementations_for_trait(&self, filter: Option, result: &mut Vec) { @@ -855,7 +939,7 @@ impl<'a, 'tcx> CrateMetadata { let filter = match filter.map(|def_id| self.reverse_translate_def_id(def_id)) { Some(Some(def_id)) => Some((def_id.krate.as_u32(), def_id.index)), Some(None) => return, - None => None + None => None, }; // FIXME(eddyb) Make this O(1) instead of O(n). @@ -864,9 +948,7 @@ impl<'a, 'tcx> CrateMetadata { continue; } - result.extend(trait_impls.impls.decode(self).map(|index| { - self.local_def_id(index) - })); + result.extend(trait_impls.impls.decode(self).map(|index| self.local_def_id(index))); if filter.is_some() { break; @@ -878,7 +960,7 @@ impl<'a, 'tcx> CrateMetadata { self.entry(id).def_key.decode(self).parent.and_then(|parent_index| { match self.entry(parent_index).kind { EntryKind::Trait(_) => Some(self.local_def_id(parent_index)), - _ => None + _ => None, } }) } @@ -889,10 +971,15 @@ impl<'a, 'tcx> CrateMetadata { } pub fn get_dylib_dependency_formats(&self) -> Vec<(CrateNum, LinkagePreference)> { - self.root.dylib_dependency_formats.decode(self).enumerate().flat_map(|(i, link)| { - let cnum = CrateNum::new(i + 1); - link.map(|link| (self.cnum_map.borrow()[cnum], link)) - }).collect() + self.root + .dylib_dependency_formats + .decode(self) + .enumerate() + .flat_map(|(i, link)| { + let cnum = CrateNum::new(i + 1); + link.map(|link| (self.cnum_map.borrow()[cnum], link)) + }) + .collect() } pub fn get_missing_lang_items(&self) -> Vec { @@ -904,7 +991,7 @@ impl<'a, 'tcx> CrateMetadata { EntryKind::Fn(data) | EntryKind::ForeignFn(data) => data.decode(self).arg_names, EntryKind::Method(data) => data.decode(self).fn_data.arg_names, - _ => LazySeq::empty() + _ => LazySeq::empty(), }; arg_names.decode(self).collect() } @@ -917,72 +1004,48 @@ impl<'a, 'tcx> CrateMetadata { let constness = match self.entry(id).kind { EntryKind::Method(data) => data.decode(self).fn_data.constness, EntryKind::Fn(data) => data.decode(self).constness, - _ => hir::Constness::NotConst + _ => hir::Constness::NotConst, }; constness == hir::Constness::Const } - pub fn is_extern_item(&self, id: DefIndex, tcx: TyCtxt<'a, 'tcx, 'tcx>) -> bool { - let item = match self.maybe_entry(id) { - Some(item) => item.decode(self), - None => return false, - }; - let applicable = match item.kind { - EntryKind::ImmStatic | - EntryKind::MutStatic | - EntryKind::ForeignImmStatic | - EntryKind::ForeignMutStatic => true, - - EntryKind::Fn(_) | EntryKind::ForeignFn(_) => { - self.get_generics(id, tcx).types.is_empty() - } - - _ => false, - }; - - if applicable { - attr::contains_extern_indicator(tcx.sess.diagnostic(), - &self.get_attributes(&item)) - } else { - false - } - } - pub fn is_foreign_item(&self, id: DefIndex) -> bool { match self.entry(id).kind { EntryKind::ForeignImmStatic | EntryKind::ForeignMutStatic | EntryKind::ForeignFn(_) => true, - _ => false + _ => false, } } pub fn is_defaulted_trait(&self, trait_id: DefIndex) -> bool { match self.entry(trait_id).kind { EntryKind::Trait(data) => data.decode(self).has_default_impl, - _ => bug!() + _ => bug!(), } } pub fn is_default_impl(&self, impl_id: DefIndex) -> bool { - match self.entry(impl_id).kind { + match self.entry(impl_id).kind { EntryKind::DefaultImpl(_) => true, - _ => false + _ => false, } } pub fn closure_kind(&self, closure_id: DefIndex) -> ty::ClosureKind { match self.entry(closure_id).kind { EntryKind::Closure(data) => data.decode(self).kind, - _ => bug!() + _ => bug!(), } } - pub fn closure_ty(&self, closure_id: DefIndex, tcx: TyCtxt<'a, 'tcx, 'tcx>) + pub fn closure_ty(&self, + closure_id: DefIndex, + tcx: TyCtxt<'a, 'tcx, 'tcx>) -> ty::ClosureTy<'tcx> { match self.entry(closure_id).kind { EntryKind::Closure(data) => data.decode(self).ty.decode((self, tcx)), - _ => bug!() + _ => bug!(), } } @@ -1025,7 +1088,8 @@ impl<'a, 'tcx> CrateMetadata { /// file they represent, just information about length, line breaks, and /// multibyte characters. This information is enough to generate valid debuginfo /// for items inlined from other crates. - pub fn imported_filemaps(&'a self, local_codemap: &codemap::CodeMap) + pub fn imported_filemaps(&'a self, + local_codemap: &codemap::CodeMap) -> Ref<'a, Vec> { { let filemaps = self.codemap_import_info.borrow(); @@ -1037,67 +1101,80 @@ impl<'a, 'tcx> CrateMetadata { let external_codemap = self.root.codemap.decode(self); let imported_filemaps = external_codemap.map(|filemap_to_import| { - // Try to find an existing FileMap that can be reused for the filemap to - // be imported. A FileMap is reusable if it is exactly the same, just - // positioned at a different offset within the codemap. - let reusable_filemap = { - local_codemap.files - .borrow() - .iter() - .find(|fm| are_equal_modulo_startpos(&fm, &filemap_to_import)) - .map(|rc| rc.clone()) - }; + // Try to find an existing FileMap that can be reused for the filemap to + // be imported. A FileMap is reusable if it is exactly the same, just + // positioned at a different offset within the codemap. + let reusable_filemap = { + local_codemap.files + .borrow() + .iter() + .find(|fm| are_equal_modulo_startpos(&fm, &filemap_to_import)) + .map(|rc| rc.clone()) + }; - match reusable_filemap { - Some(fm) => { - cstore::ImportedFileMap { - original_start_pos: filemap_to_import.start_pos, - original_end_pos: filemap_to_import.end_pos, - translated_filemap: fm - } - } - None => { - // We can't reuse an existing FileMap, so allocate a new one - // containing the information we need. - let syntax_pos::FileMap { - name, - abs_path, - start_pos, - end_pos, - lines, - multibyte_chars, - .. - } = filemap_to_import; - - let source_length = (end_pos - start_pos).to_usize(); - - // Translate line-start positions and multibyte character - // position into frame of reference local to file. - // `CodeMap::new_imported_filemap()` will then translate those - // coordinates to their new global frame of reference when the - // offset of the FileMap is known. - let mut lines = lines.into_inner(); - for pos in &mut lines { - *pos = *pos - start_pos; - } - let mut multibyte_chars = multibyte_chars.into_inner(); - for mbc in &mut multibyte_chars { - mbc.pos = mbc.pos - start_pos; + match reusable_filemap { + Some(fm) => { + + debug!("CrateMetaData::imported_filemaps reuse \ + filemap {:?} original (start_pos {:?} end_pos {:?}) \ + translated (start_pos {:?} end_pos {:?})", + filemap_to_import.name, + filemap_to_import.start_pos, filemap_to_import.end_pos, + fm.start_pos, fm.end_pos); + + cstore::ImportedFileMap { + original_start_pos: filemap_to_import.start_pos, + original_end_pos: filemap_to_import.end_pos, + translated_filemap: fm, + } } + None => { + // We can't reuse an existing FileMap, so allocate a new one + // containing the information we need. + let syntax_pos::FileMap { name, + abs_path, + start_pos, + end_pos, + lines, + multibyte_chars, + .. } = filemap_to_import; + + let source_length = (end_pos - start_pos).to_usize(); + + // Translate line-start positions and multibyte character + // position into frame of reference local to file. + // `CodeMap::new_imported_filemap()` will then translate those + // coordinates to their new global frame of reference when the + // offset of the FileMap is known. + let mut lines = lines.into_inner(); + for pos in &mut lines { + *pos = *pos - start_pos; + } + let mut multibyte_chars = multibyte_chars.into_inner(); + for mbc in &mut multibyte_chars { + mbc.pos = mbc.pos - start_pos; + } - let local_version = local_codemap.new_imported_filemap(name, - abs_path, - source_length, - lines, - multibyte_chars); - cstore::ImportedFileMap { - original_start_pos: start_pos, - original_end_pos: end_pos, - translated_filemap: local_version + let local_version = local_codemap.new_imported_filemap(name, + abs_path, + source_length, + lines, + multibyte_chars); + debug!("CrateMetaData::imported_filemaps alloc \ + filemap {:?} original (start_pos {:?} end_pos {:?}) \ + translated (start_pos {:?} end_pos {:?})", + local_version.name, start_pos, end_pos, + local_version.start_pos, local_version.end_pos); + + cstore::ImportedFileMap { + original_start_pos: start_pos, + original_end_pos: end_pos, + translated_filemap: local_version, + } } } - } - }).collect(); + }) + .collect(); // This shouldn't borrow twice, but there is no way to downgrade RefMut to Ref. *self.codemap_import_info.borrow_mut() = imported_filemaps; @@ -1135,8 +1212,7 @@ fn are_equal_modulo_startpos(fm1: &syntax_pos::FileMap, fm2: &syntax_pos::FileMa } for (mb1, mb2) in multibytes1.iter().zip(multibytes2.iter()) { - if (mb1.bytes != mb2.bytes) || - ((mb1.pos - fm1.start_pos) != (mb2.pos - fm2.start_pos)) { + if (mb1.bytes != mb2.bytes) || ((mb1.pos - fm1.start_pos) != (mb2.pos - fm2.start_pos)) { return false; } } diff --git a/src/librustc_metadata/diagnostics.rs b/src/librustc_metadata/diagnostics.rs index f52e1437ac..b2f4760727 100644 --- a/src/librustc_metadata/diagnostics.rs +++ b/src/librustc_metadata/diagnostics.rs @@ -91,185 +91,6 @@ You need to link your code to the relevant crate in order to be able to use it well, and you link to them the same way. "##, -E0466: r##" -Macro import declarations were malformed. - -Erroneous code examples: - -```compile_fail,E0466 -#[macro_use(a_macro(another_macro))] // error: invalid import declaration -extern crate some_crate; - -#[macro_use(i_want = "some_macros")] // error: invalid import declaration -extern crate another_crate; -``` - -This is a syntax error at the level of attribute declarations. The proper -syntax for macro imports is the following: - -```ignore -// In some_crate: -#[macro_export] -macro_rules! get_tacos { - ... -} - -#[macro_export] -macro_rules! get_pimientos { - ... -} - -// In your crate: -#[macro_use(get_tacos, get_pimientos)] // It imports `get_tacos` and -extern crate some_crate; // `get_pimientos` macros from some_crate -``` - -If you would like to import all exported macros, write `macro_use` with no -arguments. -"##, - -E0467: r##" -Macro reexport declarations were empty or malformed. - -Erroneous code examples: - -```compile_fail,E0467 -#[macro_reexport] // error: no macros listed for export -extern crate macros_for_good; - -#[macro_reexport(fun_macro = "foo")] // error: not a macro identifier -extern crate other_macros_for_good; -``` - -This is a syntax error at the level of attribute declarations. - -Currently, `macro_reexport` requires at least one macro name to be listed. -Unlike `macro_use`, listing no names does not reexport all macros from the -given crate. - -Decide which macros you would like to export and list them properly. - -These are proper reexport declarations: - -```ignore -#[macro_reexport(some_macro, another_macro)] -extern crate macros_for_good; -``` -"##, - -E0468: r##" -A non-root module attempts to import macros from another crate. - -Example of erroneous code: - -```compile_fail,E0468 -mod foo { - #[macro_use(helpful_macro)] // error: must be at crate root to import - extern crate some_crate; // macros from another crate - helpful_macro!(...) -} -``` - -Only `extern crate` imports at the crate root level are allowed to import -macros. - -Either move the macro import to crate root or do without the foreign macros. -This will work: - -```ignore -#[macro_use(helpful_macro)] -extern crate some_crate; - -mod foo { - helpful_macro!(...) -} -``` -"##, - -E0469: r##" -A macro listed for import was not found. - -Erroneous code example: - -```compile_fail,E0469 -#[macro_use(drink, be_merry)] // error: imported macro not found -extern crate collections; - -fn main() { - // ... -} -``` - -Either the listed macro is not contained in the imported crate, or it is not -exported from the given crate. - -This could be caused by a typo. Did you misspell the macro's name? - -Double-check the names of the macros listed for import, and that the crate -in question exports them. - -A working version would be: - -```ignore -// In some_crate crate: -#[macro_export] -macro_rules! eat { - ... -} - -#[macro_export] -macro_rules! drink { - ... -} - -// In your crate: -#[macro_use(eat, drink)] -extern crate some_crate; //ok! -``` -"##, - -E0470: r##" -A macro listed for reexport was not found. - -Erroneous code example: - -```compile_fail,E0470 -#[macro_reexport(drink, be_merry)] -extern crate collections; - -fn main() { - // ... -} -``` - -Either the listed macro is not contained in the imported crate, or it is not -exported from the given crate. - -This could be caused by a typo. Did you misspell the macro's name? - -Double-check the names of the macros listed for reexport, and that the crate -in question exports them. - -A working version: - -```ignore -// In some_crate crate: -#[macro_export] -macro_rules! eat { - ... -} - -#[macro_export] -macro_rules! drink { - ... -} - -// In your_crate: -#[macro_reexport(eat, drink)] -extern crate some_crate; -``` -"##, - } register_diagnostics! { diff --git a/src/librustc_metadata/encoder.rs b/src/librustc_metadata/encoder.rs index 0f067270b8..fdb117ef81 100644 --- a/src/librustc_metadata/encoder.rs +++ b/src/librustc_metadata/encoder.rs @@ -22,8 +22,7 @@ use rustc::mir; use rustc::traits::specialization_graph; use rustc::ty::{self, Ty, TyCtxt}; -use rustc::mir::mir_map::MirMap; -use rustc::session::config::{self, CrateTypeRustcMacro}; +use rustc::session::config::{self, CrateTypeProcMacro}; use rustc::util::nodemap::{FnvHashMap, NodeSet}; use rustc_serialize::{Encodable, Encoder, SpecializedEncoder, opaque}; @@ -51,7 +50,6 @@ pub struct EncodeContext<'a, 'tcx: 'a> { link_meta: &'a LinkMeta, cstore: &'a cstore::CStore, reachable: &'a NodeSet, - mir_map: &'a MirMap<'tcx>, lazy_state: LazyState, type_shorthands: FnvHashMap, usize>, @@ -117,7 +115,8 @@ impl<'a, 'tcx> SpecializedEncoder> for EncodeContext<'a, 'tcx> { } impl<'a, 'tcx> SpecializedEncoder> for EncodeContext<'a, 'tcx> { - fn specialized_encode(&mut self, predicates: &ty::GenericPredicates<'tcx>) + fn specialized_encode(&mut self, + predicates: &ty::GenericPredicates<'tcx>) -> Result<(), Self::Error> { predicates.parent.encode(self)?; predicates.predicates.len().encode(self)?; @@ -142,13 +141,13 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> { r } - fn emit_lazy_distance(&mut self, position: usize, min_size: usize) + fn emit_lazy_distance(&mut self, + position: usize, + min_size: usize) -> Result<(), ::Error> { let min_end = position + min_size; let distance = match self.lazy_state { - LazyState::NoNode => { - bug!("emit_lazy_distance: outside of a metadata node") - } + LazyState::NoNode => bug!("emit_lazy_distance: outside of a metadata node"), LazyState::NodeStart(start) => { assert!(min_end <= start); start - min_end @@ -172,7 +171,9 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> { } fn lazy_seq(&mut self, iter: I) -> LazySeq - where I: IntoIterator, T: Encodable { + where I: IntoIterator, + T: Encodable + { self.emit_node(|ecx, pos| { let len = iter.into_iter().map(|value| value.encode(ecx).unwrap()).count(); @@ -182,7 +183,9 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> { } fn lazy_seq_ref<'b, I, T>(&mut self, iter: I) -> LazySeq - where I: IntoIterator, T: 'b + Encodable { + where I: IntoIterator, + T: 'b + Encodable + { self.emit_node(|ecx, pos| { let len = iter.into_iter().map(|value| value.encode(ecx).unwrap()).count(); @@ -192,11 +195,15 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> { } /// Encode the given value or a previously cached shorthand. - fn encode_with_shorthand(&mut self, value: &T, variant: &U, map: M) + fn encode_with_shorthand(&mut self, + value: &T, + variant: &U, + map: M) -> Result<(), ::Error> - where M: for<'b> Fn(&'b mut Self) -> &'b mut FnvHashMap, - T: Clone + Eq + Hash, - U: Encodable { + where M: for<'b> Fn(&'b mut Self) -> &'b mut FnvHashMap, + T: Clone + Eq + Hash, + U: Encodable + { let existing_shorthand = map(self).get(value).cloned(); if let Some(shorthand) = existing_shorthand { return self.emit_usize(shorthand); @@ -208,9 +215,7 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> { // The shorthand encoding uses the same usize as the // discriminant, with an offset so they can't conflict. - let discriminant = unsafe { - intrinsics::discriminant_value(variant) - }; + let discriminant = unsafe { intrinsics::discriminant_value(variant) }; assert!(discriminant < SHORTHAND_OFFSET as u64); let shorthand = start + SHORTHAND_OFFSET; @@ -250,17 +255,17 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> { /// the right to access any information in the adt-def (including, /// e.g., the length of the various vectors). fn encode_enum_variant_info(&mut self, - (enum_did, Untracked(index)): - (DefId, Untracked)) -> Entry<'tcx> { + (enum_did, Untracked(index)): (DefId, Untracked)) + -> Entry<'tcx> { let tcx = self.tcx; let def = tcx.lookup_adt_def(enum_did); let variant = &def.variants[index]; let def_id = variant.did; let data = VariantData { - kind: variant.kind, + ctor_kind: variant.ctor_kind, disr: variant.disr_val.to_u64_unchecked(), - struct_ctor: None + struct_ctor: None, }; let enum_id = tcx.map.as_local_node_id(enum_did).unwrap(); @@ -285,24 +290,23 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> { predicates: Some(self.encode_predicates(def_id)), ast: None, - mir: None + mir: None, } } fn encode_info_for_mod(&mut self, - FromId(id, (md, attrs, vis)): - FromId<(&hir::Mod, &[ast::Attribute], &hir::Visibility)>) + FromId(id, (md, attrs, vis)): FromId<(&hir::Mod, + &[ast::Attribute], + &hir::Visibility)>) -> Entry<'tcx> { let tcx = self.tcx; let def_id = tcx.map.local_def_id(id); let data = ModData { reexports: match self.reexports.get(&id) { - Some(exports) if *vis == hir::Public => { - self.lazy_seq_ref(exports) - } - _ => LazySeq::empty() - } + Some(exports) if *vis == hir::Public => self.lazy_seq_ref(exports), + _ => LazySeq::empty(), + }, }; Entry { @@ -353,8 +357,7 @@ impl Visibility for ty::Visibility { } impl<'a, 'b, 'tcx> IndexBuilder<'a, 'b, 'tcx> { - fn encode_fields(&mut self, - adt_def_id: DefId) { + fn encode_fields(&mut self, adt_def_id: DefId) { let def = self.tcx.lookup_adt_def(adt_def_id); for (variant_index, variant) in def.variants.iter().enumerate() { for (field_index, field) in variant.fields.iter().enumerate() { @@ -374,8 +377,10 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> { /// the adt-def (including, e.g., the length of the various /// vectors). fn encode_field(&mut self, - (adt_def_id, Untracked((variant_index, field_index))): - (DefId, Untracked<(usize, usize)>)) -> Entry<'tcx> { + (adt_def_id, Untracked((variant_index, field_index))): (DefId, + Untracked<(usize, + usize)>)) + -> Entry<'tcx> { let tcx = self.tcx; let variant = &tcx.lookup_adt_def(adt_def_id).variants[variant_index]; let field = &variant.fields[field_index]; @@ -400,23 +405,26 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> { predicates: Some(self.encode_predicates(def_id)), ast: None, - mir: None + mir: None, } } - fn encode_struct_ctor(&mut self, (adt_def_id, def_id): (DefId, DefId)) - -> Entry<'tcx> { - let variant = self.tcx.lookup_adt_def(adt_def_id).struct_variant(); + fn encode_struct_ctor(&mut self, (adt_def_id, def_id): (DefId, DefId)) -> Entry<'tcx> { + let tcx = self.tcx; + let variant = tcx.lookup_adt_def(adt_def_id).struct_variant(); let data = VariantData { - kind: variant.kind, + ctor_kind: variant.ctor_kind, disr: variant.disr_val.to_u64_unchecked(), - struct_ctor: Some(def_id.index) + struct_ctor: Some(def_id.index), }; + let struct_id = tcx.map.as_local_node_id(adt_def_id).unwrap(); + let struct_vis = &tcx.map.expect_item(struct_id).vis; + Entry { kind: EntryKind::Struct(self.lazy(&data)), - visibility: ty::Visibility::Public, + visibility: struct_vis.simplify(), def_key: self.encode_def_key(def_id), attributes: LazySeq::empty(), children: LazySeq::empty(), @@ -430,7 +438,7 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> { predicates: Some(self.encode_predicates(def_id)), ast: None, - mir: None + mir: None, } } @@ -465,7 +473,7 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> { let fn_data = if let hir::MethodTraitItem(ref sig, _) = ast_item.node { FnData { constness: hir::Constness::NotConst, - arg_names: self.encode_fn_arg_names(&sig.decl) + arg_names: self.encode_fn_arg_names(&sig.decl), } } else { bug!() @@ -473,13 +481,11 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> { let data = MethodData { fn_data: fn_data, container: container(method_ty.has_body), - explicit_self: self.lazy(&method_ty.explicit_self) + explicit_self: self.lazy(&method_ty.explicit_self), }; EntryKind::Method(self.lazy(&data)) } - ty::TypeTraitItem(_) => { - EntryKind::AssociatedType(container(false)) - } + ty::TypeTraitItem(_) => EntryKind::AssociatedType(container(false)), }; Entry { @@ -493,9 +499,7 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> { ty: match trait_item { ty::ConstTraitItem(_) | - ty::MethodTraitItem(_) => { - Some(self.encode_item_type(def_id)) - } + ty::MethodTraitItem(_) => Some(self.encode_item_type(def_id)), ty::TypeTraitItem(ref associated_type) => { associated_type.ty.map(|ty| self.lazy(&ty)) } @@ -511,7 +515,7 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> { } else { None }, - mir: self.encode_mir(def_id) + mir: self.encode_mir(def_id), } } @@ -523,18 +527,16 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> { let container = match ast_item.defaultness { hir::Defaultness::Default => AssociatedContainer::ImplDefault, - hir::Defaultness::Final => AssociatedContainer::ImplFinal + hir::Defaultness::Final => AssociatedContainer::ImplFinal, }; let kind = match impl_item { - ty::ConstTraitItem(_) => { - EntryKind::AssociatedConst(container) - } + ty::ConstTraitItem(_) => EntryKind::AssociatedConst(container), ty::MethodTraitItem(ref method_ty) => { let fn_data = if let hir::ImplItemKind::Method(ref sig, _) = ast_item.node { FnData { constness: sig.constness, - arg_names: self.encode_fn_arg_names(&sig.decl) + arg_names: self.encode_fn_arg_names(&sig.decl), } } else { bug!() @@ -542,13 +544,11 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> { let data = MethodData { fn_data: fn_data, container: container, - explicit_self: self.lazy(&method_ty.explicit_self) + explicit_self: self.lazy(&method_ty.explicit_self), }; EntryKind::Method(self.lazy(&data)) } - ty::TypeTraitItem(_) => { - EntryKind::AssociatedType(container) - } + ty::TypeTraitItem(_) => EntryKind::AssociatedType(container), }; let (ast, mir) = if let ty::ConstTraitItem(_) = impl_item { @@ -574,9 +574,7 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> { ty: match impl_item { ty::ConstTraitItem(_) | - ty::MethodTraitItem(_) => { - Some(self.encode_item_type(def_id)) - } + ty::MethodTraitItem(_) => Some(self.encode_item_type(def_id)), ty::TypeTraitItem(ref associated_type) => { associated_type.ty.map(|ty| self.lazy(&ty)) } @@ -591,11 +589,7 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> { } else { None }, - mir: if mir { - self.encode_mir(def_id) - } else { - None - } + mir: if mir { self.encode_mir(def_id) } else { None }, } } @@ -609,8 +603,8 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> { })) } - fn encode_mir(&mut self, def_id: DefId) -> Option>> { - self.mir_map.map.get(&def_id).map(|mir| self.lazy(mir)) + fn encode_mir(&mut self, def_id: DefId) -> Option>> { + self.tcx.mir_map.borrow().get(&def_id).map(|mir| self.lazy(&*mir.borrow())) } // Encodes the inherent implementations of a structure, enumeration, or trait. @@ -634,8 +628,7 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> { self.tcx.lookup_deprecation(def_id).map(|depr| self.lazy(&depr)) } - fn encode_info_for_item(&mut self, - (def_id, item): (DefId, &hir::Item)) -> Entry<'tcx> { + fn encode_info_for_item(&mut self, (def_id, item): (DefId, &hir::Item)) -> Entry<'tcx> { let tcx = self.tcx; debug!("encoding info for item at {}", @@ -648,7 +641,7 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> { hir::ItemFn(ref decl, _, constness, ..) => { let data = FnData { constness: constness, - arg_names: self.encode_fn_arg_names(&decl) + arg_names: self.encode_fn_arg_names(&decl), }; EntryKind::Fn(self.lazy(&data)) @@ -662,27 +655,27 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> { hir::ItemStruct(ref struct_def, _) => { let variant = tcx.lookup_adt_def(def_id).struct_variant(); - /* Encode def_ids for each field and method - for methods, write all the stuff get_trait_method - needs to know*/ + // Encode def_ids for each field and method + // for methods, write all the stuff get_trait_method + // needs to know let struct_ctor = if !struct_def.is_struct() { Some(tcx.map.local_def_id(struct_def.id()).index) } else { None }; EntryKind::Struct(self.lazy(&VariantData { - kind: variant.kind, + ctor_kind: variant.ctor_kind, disr: variant.disr_val.to_u64_unchecked(), - struct_ctor: struct_ctor + struct_ctor: struct_ctor, })) } hir::ItemUnion(..) => { let variant = tcx.lookup_adt_def(def_id).struct_variant(); EntryKind::Union(self.lazy(&VariantData { - kind: variant.kind, + ctor_kind: variant.ctor_kind, disr: variant.disr_val.to_u64_unchecked(), - struct_ctor: None + struct_ctor: None, })) } hir::ItemDefaultImpl(..) => { @@ -690,7 +683,7 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> { polarity: hir::ImplPolarity::Positive, parent_impl: None, coerce_unsized_kind: None, - trait_ref: tcx.impl_trait_ref(def_id).map(|trait_ref| self.lazy(&trait_ref)) + trait_ref: tcx.impl_trait_ref(def_id).map(|trait_ref| self.lazy(&trait_ref)), }; EntryKind::DefaultImpl(self.lazy(&data)) @@ -712,9 +705,11 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> { let data = ImplData { polarity: polarity, parent_impl: parent, - coerce_unsized_kind: tcx.custom_coerce_unsized_kinds.borrow() - .get(&def_id).cloned(), - trait_ref: trait_ref.map(|trait_ref| self.lazy(&trait_ref)) + coerce_unsized_kind: tcx.custom_coerce_unsized_kinds + .borrow() + .get(&def_id) + .cloned(), + trait_ref: trait_ref.map(|trait_ref| self.lazy(&trait_ref)), }; EntryKind::Impl(self.lazy(&data)) @@ -726,14 +721,13 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> { paren_sugar: trait_def.paren_sugar, has_default_impl: tcx.trait_has_default_impl(def_id), trait_ref: self.lazy(&trait_def.trait_ref), - super_predicates: self.lazy(&tcx.lookup_super_predicates(def_id)) + super_predicates: self.lazy(&tcx.lookup_super_predicates(def_id)), }; EntryKind::Trait(self.lazy(&data)) } - hir::ItemExternCrate(_) | hir::ItemUse(_) => { - bug!("cannot encode info for item {:?}", item) - } + hir::ItemExternCrate(_) | + hir::ItemUse(_) => bug!("cannot encode info for item {:?}", item), }; Entry { @@ -743,9 +737,9 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> { attributes: self.encode_attributes(&item.attrs), children: match item.node { hir::ItemForeignMod(ref fm) => { - self.lazy_seq(fm.items.iter().map(|foreign_item| { - tcx.map.local_def_id(foreign_item.id).index - })) + self.lazy_seq(fm.items + .iter() + .map(|foreign_item| tcx.map.local_def_id(foreign_item.id).index)) } hir::ItemEnum(..) => { let def = self.tcx.lookup_adt_def(def_id); @@ -769,7 +763,7 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> { def_id.index })) } - _ => LazySeq::empty() + _ => LazySeq::empty(), }, stability: self.encode_stability(def_id), deprecation: self.encode_deprecation(def_id), @@ -782,20 +776,16 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> { hir::ItemEnum(..) | hir::ItemStruct(..) | hir::ItemUnion(..) | - hir::ItemImpl(..) => { - Some(self.encode_item_type(def_id)) - } - _ => None + hir::ItemImpl(..) => Some(self.encode_item_type(def_id)), + _ => None, }, inherent_impls: self.encode_inherent_implementations(def_id), variances: match item.node { hir::ItemEnum(..) | hir::ItemStruct(..) | hir::ItemUnion(..) | - hir::ItemTrait(..) => { - self.encode_item_variances(def_id) - } - _ => LazySeq::empty() + hir::ItemTrait(..) => self.encode_item_variances(def_id), + _ => LazySeq::empty(), }, generics: match item.node { hir::ItemStatic(..) | @@ -806,10 +796,8 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> { hir::ItemStruct(..) | hir::ItemUnion(..) | hir::ItemImpl(..) | - hir::ItemTrait(..) => { - Some(self.encode_generics(def_id)) - } - _ => None + hir::ItemTrait(..) => Some(self.encode_generics(def_id)), + _ => None, }, predicates: match item.node { hir::ItemStatic(..) | @@ -820,10 +808,8 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> { hir::ItemStruct(..) | hir::ItemUnion(..) | hir::ItemImpl(..) | - hir::ItemTrait(..) => { - Some(self.encode_predicates(def_id)) - } - _ => None + hir::ItemTrait(..) => Some(self.encode_predicates(def_id)), + _ => None, }, ast: match item.node { @@ -831,12 +817,10 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> { hir::ItemFn(_, _, hir::Constness::Const, ..) => { Some(self.encode_inlined_item(InlinedItemRef::Item(def_id, item))) } - _ => None + _ => None, }, mir: match item.node { - hir::ItemConst(..) => { - self.encode_mir(def_id) - } + hir::ItemConst(..) => self.encode_mir(def_id), hir::ItemFn(_, _, constness, _, ref generics, _) => { let tps_len = generics.ty_params.len(); let needs_inline = tps_len > 0 || attr::requests_inline(&item.attrs); @@ -846,8 +830,8 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> { None } } - _ => None - } + _ => None, + }, } } } @@ -857,8 +841,7 @@ impl<'a, 'b, 'tcx> IndexBuilder<'a, 'b, 'tcx> { /// encode some sub-items. Usually we want some info from the item /// so it's easier to do that here then to wait until we would encounter /// normally in the visitor walk. - fn encode_addl_info_for_item(&mut self, - item: &hir::Item) { + fn encode_addl_info_for_item(&mut self, item: &hir::Item) { let def_id = self.tcx.map.local_def_id(item.id); match item.node { hir::ItemStatic(..) | @@ -885,19 +868,12 @@ impl<'a, 'b, 'tcx> IndexBuilder<'a, 'b, 'tcx> { hir::ItemStruct(ref struct_def, _) => { self.encode_fields(def_id); - // If this is a tuple-like struct, encode the type of the constructor. - match self.tcx.lookup_adt_def(def_id).struct_variant().kind { - ty::VariantKind::Struct => { - // no value for structs like struct Foo { ... } - } - ty::VariantKind::Tuple | ty::VariantKind::Unit => { - // there is a value for structs like `struct - // Foo()` and `struct Foo` - let ctor_def_id = self.tcx.map.local_def_id(struct_def.id()); - self.record(ctor_def_id, - EncodeContext::encode_struct_ctor, - (def_id, ctor_def_id)); - } + // If the struct has a constructor, encode it. + if !struct_def.is_struct() { + let ctor_def_id = self.tcx.map.local_def_id(struct_def.id()); + self.record(ctor_def_id, + EncodeContext::encode_struct_ctor, + (def_id, ctor_def_id)); } } hir::ItemUnion(..) => { @@ -933,12 +909,12 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> { hir::ForeignItemFn(ref fndecl, _) => { let data = FnData { constness: hir::Constness::NotConst, - arg_names: self.encode_fn_arg_names(&fndecl) + arg_names: self.encode_fn_arg_names(&fndecl), }; EntryKind::ForeignFn(self.lazy(&data)) } hir::ForeignItemStatic(_, true) => EntryKind::ForeignMutStatic, - hir::ForeignItemStatic(_, false) => EntryKind::ForeignImmStatic + hir::ForeignItemStatic(_, false) => EntryKind::ForeignImmStatic, }; Entry { @@ -957,7 +933,7 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> { predicates: Some(self.encode_predicates(def_id)), ast: None, - mir: None + mir: None, } } } @@ -975,10 +951,9 @@ impl<'a, 'b, 'tcx> Visitor<'tcx> for EncodeVisitor<'a, 'b, 'tcx> { intravisit::walk_item(self, item); let def_id = self.index.tcx.map.local_def_id(item.id); match item.node { - hir::ItemExternCrate(_) | hir::ItemUse(_) => (), // ignore these - _ => self.index.record(def_id, - EncodeContext::encode_info_for_item, - (def_id, item)), + hir::ItemExternCrate(_) | + hir::ItemUse(_) => (), // ignore these + _ => self.index.record(def_id, EncodeContext::encode_info_for_item, (def_id, item)), } self.index.encode_addl_info_for_item(item); } @@ -999,9 +974,7 @@ impl<'a, 'b, 'tcx> IndexBuilder<'a, 'b, 'tcx> { fn encode_info_for_ty(&mut self, ty: &hir::Ty) { if let hir::TyImplTrait(_) = ty.node { let def_id = self.tcx.map.local_def_id(ty.id); - self.record(def_id, - EncodeContext::encode_info_for_anon_ty, - def_id); + self.record(def_id, EncodeContext::encode_info_for_anon_ty, def_id); } } @@ -1009,11 +982,9 @@ impl<'a, 'b, 'tcx> IndexBuilder<'a, 'b, 'tcx> { match expr.node { hir::ExprClosure(..) => { let def_id = self.tcx.map.local_def_id(expr.id); - self.record(def_id, - EncodeContext::encode_info_for_closure, - def_id); + self.record(def_id, EncodeContext::encode_info_for_closure, def_id); } - _ => { } + _ => {} } } } @@ -1036,7 +1007,7 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> { predicates: Some(self.encode_predicates(def_id)), ast: None, - mir: None + mir: None, } } @@ -1045,7 +1016,7 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> { let data = ClosureData { kind: tcx.closure_kind(def_id), - ty: self.lazy(&tcx.tables.borrow().closure_tys[&def_id]) + ty: self.lazy(&tcx.tables().closure_tys[&def_id]), }; Entry { @@ -1064,7 +1035,7 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> { predicates: None, ast: None, - mir: self.encode_mir(def_id) + mir: self.encode_mir(def_id), } } @@ -1074,9 +1045,7 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> { index.record(DefId::local(CRATE_DEF_INDEX), EncodeContext::encode_info_for_mod, FromId(CRATE_NODE_ID, (&krate.module, &krate.attrs, &hir::Public))); - let mut visitor = EncodeVisitor { - index: index, - }; + let mut visitor = EncodeVisitor { index: index }; krate.visit_all_items(&mut visitor); visitor.index.into_items() } @@ -1086,8 +1055,7 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> { } fn encode_crate_deps(&mut self) -> LazySeq { - fn get_ordered_deps(cstore: &cstore::CStore) - -> Vec<(CrateNum, Rc)> { + fn get_ordered_deps(cstore: &cstore::CStore) -> Vec<(CrateNum, Rc)> { // Pull the cnums and name,vers,hash out of cstore let mut deps = Vec::new(); cstore.iter_crate_data(|cnum, val| { @@ -1116,13 +1084,12 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> { CrateDep { name: syntax::parse::token::intern(dep.name()), hash: dep.hash(), - explicitly_linked: dep.explicitly_linked.get() + explicitly_linked: dep.explicitly_linked.get(), } })) } - fn encode_lang_items(&mut self) - -> (LazySeq<(DefIndex, usize)>, LazySeq) { + fn encode_lang_items(&mut self) -> (LazySeq<(DefIndex, usize)>, LazySeq) { let tcx = self.tcx; let lang_items = tcx.lang_items.items().iter(); (self.lazy_seq(lang_items.enumerate().filter_map(|(i, &opt_def_id)| { @@ -1132,7 +1099,8 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> { } } None - })), self.lazy_seq_ref(&tcx.lang_items.missing)) + })), + self.lazy_seq_ref(&tcx.lang_items.missing)) } fn encode_native_libraries(&mut self) -> LazySeq<(NativeLibraryKind, String)> { @@ -1140,9 +1108,7 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> { self.lazy_seq(used_libraries.into_iter().filter_map(|(lib, kind)| { match kind { cstore::NativeStatic => None, // these libraries are not propagated - cstore::NativeFramework | cstore::NativeUnknown => { - Some((kind, lib)) - } + cstore::NativeFramework | cstore::NativeUnknown => Some((kind, lib)), } })) } @@ -1150,13 +1116,15 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> { fn encode_codemap(&mut self) -> LazySeq { let codemap = self.tcx.sess.codemap(); let all_filemaps = codemap.files.borrow(); - self.lazy_seq_ref(all_filemaps.iter().filter(|filemap| { - // 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 - // crate will import them from their original source. - !filemap.lines.borrow().is_empty() && !filemap.is_imported() - }).map(|filemap| &**filemap)) + self.lazy_seq_ref(all_filemaps.iter() + .filter(|filemap| { + // 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 + // crate will import them from their original source. + !filemap.lines.borrow().is_empty() && !filemap.is_imported() + }) + .map(|filemap| &**filemap)) } /// Serialize the text of the exported macros @@ -1167,15 +1135,15 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> { name: def.name, attrs: def.attrs.to_vec(), span: def.span, - body: ::syntax::print::pprust::tts_to_string(&def.body) + body: ::syntax::print::pprust::tts_to_string(&def.body), } })) } } -struct ImplVisitor<'a, 'tcx:'a> { +struct ImplVisitor<'a, 'tcx: 'a> { tcx: TyCtxt<'a, 'tcx, 'tcx>, - impls: FnvHashMap> + impls: FnvHashMap>, } impl<'a, 'tcx, 'v> Visitor<'v> for ImplVisitor<'a, 'tcx> { @@ -1183,7 +1151,8 @@ impl<'a, 'tcx, 'v> Visitor<'v> for ImplVisitor<'a, 'tcx> { if let hir::ItemImpl(..) = item.node { let impl_id = self.tcx.map.local_def_id(item.id); if let Some(trait_ref) = self.tcx.impl_trait_ref(impl_id) { - self.impls.entry(trait_ref.def_id) + self.impls + .entry(trait_ref.def_id) .or_insert(vec![]) .push(impl_id.index); } @@ -1196,16 +1165,19 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> { fn encode_impls(&mut self) -> LazySeq { let mut visitor = ImplVisitor { tcx: self.tcx, - impls: FnvHashMap() + impls: FnvHashMap(), }; self.tcx.map.krate().visit_all_items(&mut visitor); - let all_impls: Vec<_> = visitor.impls.into_iter().map(|(trait_def_id, impls)| { - TraitImpls { - trait_id: (trait_def_id.krate.as_u32(), trait_def_id.index), - impls: self.lazy_seq(impls) - } - }).collect(); + let all_impls: Vec<_> = visitor.impls + .into_iter() + .map(|(trait_def_id, impls)| { + TraitImpls { + trait_id: (trait_def_id.krate.as_u32(), trait_def_id.index), + impls: self.lazy_seq(impls), + } + }) + .collect(); self.lazy_seq(all_impls) } @@ -1235,7 +1207,7 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> { } })) } - None => LazySeq::empty() + None => LazySeq::empty(), } } @@ -1286,18 +1258,19 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> { let tcx = self.tcx; let link_meta = self.link_meta; - let is_rustc_macro = tcx.sess.crate_types.borrow().contains(&CrateTypeRustcMacro); + let is_proc_macro = tcx.sess.crate_types.borrow().contains(&CrateTypeProcMacro); let root = self.lazy(&CrateRoot { - rustc_version: RUSTC_VERSION.to_string(), + rustc_version: rustc_version(), name: link_meta.crate_name.clone(), triple: tcx.sess.opts.target_triple.clone(), hash: link_meta.crate_hash, disambiguator: tcx.sess.local_crate_disambiguator().to_string(), - panic_strategy: tcx.sess.opts.cg.panic.clone(), - plugin_registrar_fn: tcx.sess.plugin_registrar_fn.get().map(|id| { - tcx.map.local_def_id(id).index - }), - macro_derive_registrar: if is_rustc_macro { + panic_strategy: tcx.sess.panic_strategy(), + plugin_registrar_fn: tcx.sess + .plugin_registrar_fn + .get() + .map(|id| tcx.map.local_def_id(id).index), + macro_derive_registrar: if is_proc_macro { let id = tcx.sess.derive_registrar_fn.get().unwrap(); Some(tcx.map.local_def_id(id).index) } else { @@ -1371,8 +1344,8 @@ pub fn encode_metadata<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, cstore: &cstore::CStore, reexports: &def::ExportMap, link_meta: &LinkMeta, - reachable: &NodeSet, - mir_map: &MirMap<'tcx>) -> Vec { + reachable: &NodeSet) + -> Vec { let mut cursor = Cursor::new(vec![]); cursor.write_all(METADATA_HEADER).unwrap(); @@ -1380,17 +1353,17 @@ pub fn encode_metadata<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, cursor.write_all(&[0, 0, 0, 0]).unwrap(); let root = EncodeContext { - opaque: opaque::Encoder::new(&mut cursor), - tcx: tcx, - reexports: reexports, - link_meta: link_meta, - cstore: cstore, - reachable: reachable, - mir_map: mir_map, - lazy_state: LazyState::NoNode, - type_shorthands: Default::default(), - predicate_shorthands: Default::default() - }.encode_crate_root(); + opaque: opaque::Encoder::new(&mut cursor), + tcx: tcx, + reexports: reexports, + link_meta: link_meta, + cstore: cstore, + reachable: reachable, + lazy_state: LazyState::NoNode, + type_shorthands: Default::default(), + predicate_shorthands: Default::default(), + } + .encode_crate_root(); let mut result = cursor.into_inner(); // Encode the root position. @@ -1398,8 +1371,8 @@ pub fn encode_metadata<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, let pos = root.position; result[header + 0] = (pos >> 24) as u8; result[header + 1] = (pos >> 16) as u8; - result[header + 2] = (pos >> 8) as u8; - result[header + 3] = (pos >> 0) as u8; + result[header + 2] = (pos >> 8) as u8; + result[header + 3] = (pos >> 0) as u8; result } diff --git a/src/librustc_metadata/index.rs b/src/librustc_metadata/index.rs index ef83251f51..53e6988c75 100644 --- a/src/librustc_metadata/index.rs +++ b/src/librustc_metadata/index.rs @@ -28,9 +28,7 @@ pub struct Index { impl Index { pub fn new(max_index: usize) -> Index { - Index { - positions: vec![u32::MAX; max_index] - } + Index { positions: vec![u32::MAX; max_index] } } pub fn record(&mut self, def_id: DefId, entry: Lazy) { @@ -46,7 +44,9 @@ impl Index { assert!(self.positions[item] == u32::MAX, "recorded position for item {:?} twice, first at {:?} and now at {:?}", - item, self.positions[item], position); + item, + self.positions[item], + position); self.positions[item] = position.to_le(); } @@ -67,7 +67,8 @@ impl<'tcx> LazySeq { let index = def_index.as_usize(); debug!("Index::lookup: index={:?} words.len={:?}", - index, words.len()); + index, + words.len()); let position = u32::from_le(words[index]); if position == u32::MAX { @@ -79,8 +80,9 @@ impl<'tcx> LazySeq { } } - pub fn iter_enumerated<'a>(&self, bytes: &'a [u8]) - -> impl Iterator>)> + 'a { + pub fn iter_enumerated<'a>(&self, + bytes: &'a [u8]) + -> impl Iterator>)> + 'a { let words = &bytes_to_words(&bytes[self.position..])[..self.len]; words.iter().enumerate().filter_map(|(index, &position)| { if position == u32::MAX { diff --git a/src/librustc_metadata/index_builder.rs b/src/librustc_metadata/index_builder.rs index aeb6f63252..9938e20d18 100644 --- a/src/librustc_metadata/index_builder.rs +++ b/src/librustc_metadata/index_builder.rs @@ -138,11 +138,11 @@ pub trait DepGraphRead { } impl DepGraphRead for DefId { - fn read(&self, _tcx: TyCtxt) { } + fn read(&self, _tcx: TyCtxt) {} } impl DepGraphRead for ast::NodeId { - fn read(&self, _tcx: TyCtxt) { } + fn read(&self, _tcx: TyCtxt) {} } impl DepGraphRead for Option @@ -179,8 +179,8 @@ macro_rules! read_tuple { } } } -read_tuple!(A,B); -read_tuple!(A,B,C); +read_tuple!(A, B); +read_tuple!(A, B, C); macro_rules! read_hir { ($t:ty) => { @@ -208,7 +208,7 @@ read_hir!(hir::ForeignItem); pub struct Untracked(pub T); impl DepGraphRead for Untracked { - fn read(&self, _tcx: TyCtxt) { } + fn read(&self, _tcx: TyCtxt) {} } /// Newtype that can be used to package up misc data extracted from a diff --git a/src/librustc_metadata/lib.rs b/src/librustc_metadata/lib.rs index 50e1cbf565..2fd40181d7 100644 --- a/src/librustc_metadata/lib.rs +++ b/src/librustc_metadata/lib.rs @@ -17,34 +17,36 @@ html_root_url = "https://doc.rust-lang.org/nightly/")] #![cfg_attr(not(stage0), deny(warnings))] +#![feature(box_patterns)] #![feature(conservative_impl_trait)] #![feature(core_intrinsics)] -#![feature(box_patterns)] -#![feature(dotdot_in_tuple_patterns)] +#![cfg_attr(stage0, feature(dotdot_in_tuple_patterns))] +#![feature(proc_macro_internals)] +#![feature(proc_macro_lib)] #![cfg_attr(stage0, feature(question_mark))] #![feature(quote)] #![feature(rustc_diagnostic_macros)] -#![feature(rustc_macro_lib)] -#![feature(rustc_macro_internals)] #![feature(rustc_private)] #![feature(specialization)] #![feature(staged_api)] -#[macro_use] extern crate log; -#[macro_use] extern crate syntax; +#[macro_use] +extern crate log; +#[macro_use] +extern crate syntax; extern crate syntax_pos; extern crate flate; extern crate serialize as rustc_serialize; // used by deriving extern crate rustc_errors as errors; extern crate syntax_ext; +extern crate proc_macro; #[macro_use] extern crate rustc; -extern crate rustc_data_structures; extern crate rustc_back; -extern crate rustc_llvm; -extern crate rustc_macro; extern crate rustc_const_math; +extern crate rustc_data_structures; +extern crate rustc_llvm; mod diagnostics; @@ -53,12 +55,11 @@ mod index_builder; mod index; mod encoder; mod decoder; -mod csearch; +mod cstore_impl; mod schema; pub mod creader; pub mod cstore; -pub mod loader; -pub mod macro_import; +pub mod locator; __build_diagnostic_array! { librustc_metadata, DIAGNOSTICS } diff --git a/src/librustc_metadata/loader.rs b/src/librustc_metadata/locator.rs similarity index 79% rename from src/librustc_metadata/loader.rs rename to src/librustc_metadata/locator.rs index fc94cec916..0461d7ec06 100644 --- a/src/librustc_metadata/loader.rs +++ b/src/librustc_metadata/locator.rs @@ -210,10 +210,11 @@ //! //! That's the general overview of loading crates in the compiler, but it's by //! no means all of the necessary details. Take a look at the rest of -//! metadata::loader or metadata::creader for all the juicy details! +//! metadata::locator or metadata::creader for all the juicy details! use cstore::MetadataBlob; -use schema::{METADATA_HEADER, RUSTC_VERSION}; +use creader::Library; +use schema::{METADATA_HEADER, rustc_version}; use rustc::hir::svh::Svh; use rustc::session::Session; @@ -263,12 +264,6 @@ pub struct Context<'a> { pub should_match_name: bool, } -pub struct Library { - pub dylib: Option<(PathBuf, PathKind)>, - pub rlib: Option<(PathBuf, PathKind)>, - pub metadata: MetadataBlob, -} - pub struct ArchiveMetadata { _archive: ArchiveRO, // points into self._archive @@ -278,7 +273,7 @@ pub struct ArchiveMetadata { pub struct CratePaths { pub ident: String, pub dylib: Option, - pub rlib: Option + pub rlib: Option, } pub const METADATA_FILENAME: &'static str = "rust.metadata.bin"; @@ -286,14 +281,14 @@ pub const METADATA_FILENAME: &'static str = "rust.metadata.bin"; #[derive(Copy, Clone, PartialEq)] enum CrateFlavor { Rlib, - Dylib + Dylib, } impl fmt::Display for CrateFlavor { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { f.write_str(match *self { CrateFlavor::Rlib => "rlib", - CrateFlavor::Dylib => "dylib" + CrateFlavor::Dylib => "dylib", }) } } @@ -301,10 +296,10 @@ impl fmt::Display for CrateFlavor { impl CratePaths { fn paths(&self) -> Vec { match (&self.dylib, &self.rlib) { - (&None, &None) => vec!(), + (&None, &None) => vec![], (&Some(ref p), &None) | - (&None, &Some(ref p)) => vec!(p.clone()), - (&Some(ref p1), &Some(ref p2)) => vec!(p1.clone(), p2.clone()), + (&None, &Some(ref p)) => vec![p.clone()], + (&Some(ref p1), &Some(ref p2)) => vec![p1.clone(), p2.clone()], } } } @@ -315,59 +310,78 @@ impl<'a> Context<'a> { } pub fn load_library_crate(&mut self) -> Library { - self.find_library_crate().unwrap_or_else(|| self.report_load_errs()) + self.find_library_crate().unwrap_or_else(|| self.report_errs()) } - pub fn report_load_errs(&mut self) -> ! { + pub fn report_errs(&mut self) -> ! { let add = match self.root { &None => String::new(), - &Some(ref r) => format!(" which `{}` depends on", - r.ident) + &Some(ref r) => format!(" which `{}` depends on", r.ident), }; let mut err = if !self.rejected_via_hash.is_empty() { - struct_span_err!(self.sess, self.span, E0460, + struct_span_err!(self.sess, + self.span, + E0460, "found possibly newer version of crate `{}`{}", - self.ident, add) + self.ident, + add) } else if !self.rejected_via_triple.is_empty() { - struct_span_err!(self.sess, self.span, E0461, + struct_span_err!(self.sess, + self.span, + E0461, "couldn't find crate `{}` with expected target triple {}{}", - self.ident, self.triple, add) + self.ident, + self.triple, + add) } else if !self.rejected_via_kind.is_empty() { - struct_span_err!(self.sess, self.span, E0462, + struct_span_err!(self.sess, + self.span, + E0462, "found staticlib `{}` instead of rlib or dylib{}", - self.ident, add) + self.ident, + add) } else if !self.rejected_via_version.is_empty() { - struct_span_err!(self.sess, self.span, E0514, + struct_span_err!(self.sess, + self.span, + E0514, "found crate `{}` compiled by an incompatible version of rustc{}", - self.ident, add) + self.ident, + add) } else { - let mut err = struct_span_err!(self.sess, self.span, E0463, + let mut err = struct_span_err!(self.sess, + self.span, + E0463, "can't find crate for `{}`{}", - self.ident, add); + self.ident, + add); err.span_label(self.span, &format!("can't find crate")); err }; if !self.rejected_via_triple.is_empty() { let mismatches = self.rejected_via_triple.iter(); - for (i, &CrateMismatch{ ref path, ref got }) in mismatches.enumerate() { + for (i, &CrateMismatch { ref path, ref got }) in mismatches.enumerate() { err.note(&format!("crate `{}`, path #{}, triple {}: {}", - self.ident, i+1, got, path.display())); + self.ident, + i + 1, + got, + path.display())); } } if !self.rejected_via_hash.is_empty() { err.note("perhaps that crate needs to be recompiled?"); let mismatches = self.rejected_via_hash.iter(); - for (i, &CrateMismatch{ ref path, .. }) in mismatches.enumerate() { - err.note(&format!("crate `{}` path #{}: {}", - self.ident, i+1, path.display())); + for (i, &CrateMismatch { ref path, .. }) in mismatches.enumerate() { + err.note(&format!("crate `{}` path #{}: {}", self.ident, i + 1, path.display())); } match self.root { &None => {} &Some(ref r) => { for (i, path) in r.paths().iter().enumerate() { err.note(&format!("crate `{}` path #{}: {}", - r.ident, i+1, path.display())); + r.ident, + i + 1, + path.display())); } } } @@ -376,17 +390,19 @@ impl<'a> Context<'a> { err.help("please recompile that crate using --crate-type lib"); let mismatches = self.rejected_via_kind.iter(); for (i, &CrateMismatch { ref path, .. }) in mismatches.enumerate() { - err.note(&format!("crate `{}` path #{}: {}", - self.ident, i+1, path.display())); + err.note(&format!("crate `{}` path #{}: {}", self.ident, i + 1, path.display())); } } if !self.rejected_via_version.is_empty() { err.help(&format!("please recompile that crate using this compiler ({})", - RUSTC_VERSION)); + rustc_version())); let mismatches = self.rejected_via_version.iter(); for (i, &CrateMismatch { ref path, ref got }) in mismatches.enumerate() { err.note(&format!("crate `{}` path #{}: {} compiled by {:?}", - self.ident, i+1, path.display(), got)); + self.ident, + i + 1, + path.display(), + got)); } } @@ -415,7 +431,7 @@ impl<'a> Context<'a> { let staticlib_prefix = format!("{}{}", staticpair.0, self.crate_name); let mut candidates = FnvHashMap(); - let mut staticlibs = vec!(); + let mut staticlibs = vec![]; // First, find all possible candidate rlibs and dylibs purely based on // the name of the files themselves. We're trying to match against an @@ -435,38 +451,36 @@ impl<'a> Context<'a> { None => return FileDoesntMatch, Some(file) => file, }; - let (hash, rlib) = if file.starts_with(&rlib_prefix[..]) && - file.ends_with(".rlib") { - (&file[(rlib_prefix.len()) .. (file.len() - ".rlib".len())], - true) + let (hash, rlib) = if file.starts_with(&rlib_prefix[..]) && file.ends_with(".rlib") { + (&file[(rlib_prefix.len())..(file.len() - ".rlib".len())], true) } else if file.starts_with(&dylib_prefix) && - file.ends_with(&dypair.1) { - (&file[(dylib_prefix.len()) .. (file.len() - dypair.1.len())], - false) + file.ends_with(&dypair.1) { + (&file[(dylib_prefix.len())..(file.len() - dypair.1.len())], false) } else { - if file.starts_with(&staticlib_prefix[..]) && - file.ends_with(&staticpair.1) { + if file.starts_with(&staticlib_prefix[..]) && file.ends_with(&staticpair.1) { staticlibs.push(CrateMismatch { path: path.to_path_buf(), - got: "static".to_string() + got: "static".to_string(), }); } - return FileDoesntMatch + return FileDoesntMatch; }; info!("lib candidate: {}", path.display()); let hash_str = hash.to_string(); let slot = candidates.entry(hash_str) - .or_insert_with(|| (FnvHashMap(), FnvHashMap())); + .or_insert_with(|| (FnvHashMap(), FnvHashMap())); let (ref mut rlibs, ref mut dylibs) = *slot; - fs::canonicalize(path).map(|p| { - if rlib { - rlibs.insert(p, kind); - } else { - dylibs.insert(p, kind); - } - FileMatches - }).unwrap_or(FileDoesntMatch) + fs::canonicalize(path) + .map(|p| { + if rlib { + rlibs.insert(p, kind); + } else { + dylibs.insert(p, kind); + } + FileMatches + }) + .unwrap_or(FileDoesntMatch) }); self.rejected_via_kind.extend(staticlibs); @@ -484,11 +498,12 @@ impl<'a> Context<'a> { let rlib = self.extract_one(rlibs, CrateFlavor::Rlib, &mut slot); let dylib = self.extract_one(dylibs, CrateFlavor::Dylib, &mut slot); if let Some((h, m)) = slot { - libraries.insert(h, Library { - dylib: dylib, - rlib: rlib, - metadata: m, - }); + libraries.insert(h, + Library { + dylib: dylib, + rlib: rlib, + metadata: m, + }); } } @@ -499,7 +514,9 @@ impl<'a> Context<'a> { 0 => None, 1 => Some(libraries.into_iter().next().unwrap().1), _ => { - let mut err = struct_span_err!(self.sess, self.span, E0464, + let mut err = struct_span_err!(self.sess, + self.span, + E0464, "multiple matching crates for `{}`", self.crate_name); err.note("candidates:"); @@ -526,8 +543,11 @@ impl<'a> Context<'a> { // read the metadata from it if `*slot` is `None`. If the metadata couldn't // be read, it is assumed that the file isn't a valid rust library (no // errors are emitted). - fn extract_one(&mut self, m: FnvHashMap, flavor: CrateFlavor, - slot: &mut Option<(Svh, MetadataBlob)>) -> Option<(PathBuf, PathKind)> { + fn extract_one(&mut self, + m: FnvHashMap, + flavor: CrateFlavor, + slot: &mut Option<(Svh, MetadataBlob)>) + -> Option<(PathBuf, PathKind)> { let mut ret: Option<(PathBuf, PathKind)> = None; let mut error = 0; @@ -537,9 +557,9 @@ impl<'a> Context<'a> { // read both, but reading dylib metadata is quite // slow. if m.is_empty() { - return None + return None; } else if m.len() == 1 { - return Some(m.into_iter().next().unwrap()) + return Some(m.into_iter().next().unwrap()); } } @@ -552,23 +572,28 @@ impl<'a> Context<'a> { (h, blob) } else { info!("metadata mismatch"); - continue + continue; } } Err(err) => { info!("no metadata found: {}", err); - continue + continue; } }; // If we see multiple hashes, emit an error about duplicate candidates. if slot.as_ref().map_or(false, |s| s.0 != hash) { - let mut e = struct_span_err!(self.sess, self.span, E0465, + let mut e = struct_span_err!(self.sess, + self.span, + E0465, "multiple {} candidates for `{}` found", - flavor, self.crate_name); + flavor, + self.crate_name); e.span_note(self.span, &format!(r"candidate #1: {}", - ret.as_ref().unwrap().0 - .display())); + ret.as_ref() + .unwrap() + .0 + .display())); if let Some(ref mut e) = err { e.emit(); } @@ -579,9 +604,10 @@ impl<'a> Context<'a> { if error > 0 { error += 1; err.as_mut().unwrap().span_note(self.span, - &format!(r"candidate #{}: {}", error, + &format!(r"candidate #{}: {}", + error, lib.display())); - continue + continue; } *slot = Some((hash, metadata)); ret = Some((lib, kind)); @@ -597,39 +623,42 @@ impl<'a> Context<'a> { fn crate_matches(&mut self, metadata: &MetadataBlob, libpath: &Path) -> Option { let root = metadata.get_root(); - if root.rustc_version != RUSTC_VERSION { + let rustc_version = rustc_version(); + if root.rustc_version != rustc_version { info!("Rejecting via version: expected {} got {}", - RUSTC_VERSION, root.rustc_version); + rustc_version, + root.rustc_version); self.rejected_via_version.push(CrateMismatch { path: libpath.to_path_buf(), - got: root.rustc_version + got: root.rustc_version, }); return None; } if self.should_match_name { if self.crate_name != root.name { - info!("Rejecting via crate name"); return None; + info!("Rejecting via crate name"); + return None; } } if root.triple != self.triple { info!("Rejecting via crate triple: expected {} got {}", - self.triple, root.triple); + self.triple, + root.triple); self.rejected_via_triple.push(CrateMismatch { path: libpath.to_path_buf(), - got: root.triple + got: root.triple, }); return None; } if let Some(myhash) = self.hash { if *myhash != root.hash { - info!("Rejecting via hash: expected {} got {}", - *myhash, root.hash); + info!("Rejecting via hash: expected {} got {}", *myhash, root.hash); self.rejected_via_hash.push(CrateMismatch { path: libpath.to_path_buf(), - got: myhash.to_string() + got: myhash.to_string(), }); return None; } @@ -653,8 +682,8 @@ impl<'a> Context<'a> { (t.options.staticlib_prefix.clone(), t.options.staticlib_suffix.clone()) } - fn find_commandline_library<'b, LOCS> (&mut self, locs: LOCS) -> Option - where LOCS: Iterator + fn find_commandline_library<'b, LOCS>(&mut self, locs: LOCS) -> Option + where LOCS: Iterator { // First, filter out all libraries that look suspicious. We only accept // files which actually exist that have the correct naming scheme for @@ -667,30 +696,33 @@ impl<'a> Context<'a> { let locs = locs.map(|l| PathBuf::from(l)).filter(|loc| { if !loc.exists() { sess.err(&format!("extern location for {} does not exist: {}", - self.crate_name, loc.display())); + self.crate_name, + loc.display())); return false; } let file = match loc.file_name().and_then(|s| s.to_str()) { Some(file) => file, None => { sess.err(&format!("extern location for {} is not a file: {}", - self.crate_name, loc.display())); + self.crate_name, + loc.display())); return false; } }; if file.starts_with("lib") && file.ends_with(".rlib") { - return true + return true; } else { let (ref prefix, ref suffix) = dylibname; - if file.starts_with(&prefix[..]) && - file.ends_with(&suffix[..]) { - return true + if file.starts_with(&prefix[..]) && file.ends_with(&suffix[..]) { + return true; } } sess.struct_err(&format!("extern location for {} is of an unknown type: {}", - self.crate_name, loc.display())) + self.crate_name, + loc.display())) .help(&format!("file name should be lib*.rlib or {}*.{}", - dylibname.0, dylibname.1)) + dylibname.0, + dylibname.1)) .emit(); false }); @@ -699,11 +731,9 @@ impl<'a> Context<'a> { // there's at most one rlib and at most one dylib. for loc in locs { if loc.file_name().unwrap().to_str().unwrap().ends_with(".rlib") { - rlibs.insert(fs::canonicalize(&loc).unwrap(), - PathKind::ExternFlag); + rlibs.insert(fs::canonicalize(&loc).unwrap(), PathKind::ExternFlag); } else { - dylibs.insert(fs::canonicalize(&loc).unwrap(), - PathKind::ExternFlag); + dylibs.insert(fs::canonicalize(&loc).unwrap(), PathKind::ExternFlag); } } }; @@ -713,13 +743,17 @@ impl<'a> Context<'a> { let rlib = self.extract_one(rlibs, CrateFlavor::Rlib, &mut slot); let dylib = self.extract_one(dylibs, CrateFlavor::Dylib, &mut slot); - if rlib.is_none() && dylib.is_none() { return None } + if rlib.is_none() && dylib.is_none() { + return None; + } match slot { - Some((_, metadata)) => Some(Library { - dylib: dylib, - rlib: rlib, - metadata: metadata, - }), + Some((_, metadata)) => { + Some(Library { + dylib: dylib, + rlib: rlib, + metadata: metadata, + }) + } None => None, } } @@ -732,9 +766,9 @@ pub fn note_crate_name(err: &mut DiagnosticBuilder, name: &str) { impl ArchiveMetadata { fn new(ar: ArchiveRO) -> Option { let data = { - let section = ar.iter().filter_map(|s| s.ok()).find(|sect| { - sect.name() == Some(METADATA_FILENAME) - }); + let section = ar.iter() + .filter_map(|s| s.ok()) + .find(|sect| sect.name() == Some(METADATA_FILENAME)); match section { Some(s) => s.data() as *const [u8], None => { @@ -750,12 +784,14 @@ impl ArchiveMetadata { }) } - pub fn as_slice<'a>(&'a self) -> &'a [u8] { unsafe { &*self.data } } + pub fn as_slice<'a>(&'a self) -> &'a [u8] { + unsafe { &*self.data } + } } -fn verify_decompressed_encoding_version(blob: &MetadataBlob, filename: &Path) - -> Result<(), String> -{ +fn verify_decompressed_encoding_version(blob: &MetadataBlob, + filename: &Path) + -> Result<(), String> { if !blob.is_compatible() { Err((format!("incompatible metadata version found: '{}'", filename.display()))) @@ -765,16 +801,21 @@ fn verify_decompressed_encoding_version(blob: &MetadataBlob, filename: &Path) } // Just a small wrapper to time how long reading metadata takes. -fn get_metadata_section(target: &Target, flavor: CrateFlavor, filename: &Path) +fn get_metadata_section(target: &Target, + flavor: CrateFlavor, + filename: &Path) -> Result { let start = Instant::now(); let ret = get_metadata_section_imp(target, flavor, filename); - info!("reading {:?} => {:?}", filename.file_name().unwrap(), + info!("reading {:?} => {:?}", + filename.file_name().unwrap(), start.elapsed()); - return ret + return ret; } -fn get_metadata_section_imp(target: &Target, flavor: CrateFlavor, filename: &Path) +fn get_metadata_section_imp(target: &Target, + flavor: CrateFlavor, + filename: &Path) -> Result { if !filename.exists() { return Err(format!("no such file: '{}'", filename.display())); @@ -787,13 +828,11 @@ fn get_metadata_section_imp(target: &Target, flavor: CrateFlavor, filename: &Pat Some(ar) => ar, None => { debug!("llvm didn't like `{}`", filename.display()); - return Err(format!("failed to read rlib metadata: '{}'", - filename.display())); + return Err(format!("failed to read rlib metadata: '{}'", filename.display())); } }; return match ArchiveMetadata::new(archive).map(|ar| MetadataBlob::Archive(ar)) { - None => Err(format!("failed to read rlib metadata: '{}'", - filename.display())), + None => Err(format!("failed to read rlib metadata: '{}'", filename.display())), Some(blob) => { verify_decompressed_encoding_version(&blob, filename)?; Ok(blob) @@ -804,22 +843,19 @@ fn get_metadata_section_imp(target: &Target, flavor: CrateFlavor, filename: &Pat let buf = common::path2cstr(filename); let mb = llvm::LLVMRustCreateMemoryBufferWithContentsOfFile(buf.as_ptr()); if mb as isize == 0 { - return Err(format!("error reading library: '{}'", - filename.display())) + return Err(format!("error reading library: '{}'", filename.display())); } let of = match ObjectFile::new(mb) { Some(of) => of, _ => { - return Err((format!("provided path not an object file: '{}'", - filename.display()))) + return Err((format!("provided path not an object file: '{}'", filename.display()))) } }; let si = mk_section_iter(of.llof); while llvm::LLVMIsSectionIteratorAtEnd(of.llof, si.llsi) == False { let mut name_buf = ptr::null(); let name_len = llvm::LLVMRustGetSectionName(si.llsi, &mut name_buf); - let name = slice::from_raw_parts(name_buf as *const u8, - name_len as usize).to_vec(); + let name = slice::from_raw_parts(name_buf as *const u8, name_len as usize).to_vec(); let name = String::from_utf8(name).unwrap(); debug!("get_metadata_section: name {}", name); if read_meta_section_name(target) == name { @@ -827,8 +863,7 @@ fn get_metadata_section_imp(target: &Target, flavor: CrateFlavor, filename: &Pat let csz = llvm::LLVMGetSectionSize(si.llsi) as usize; let cvbuf: *const u8 = cbuf as *const u8; let vlen = METADATA_HEADER.len(); - debug!("checking {} bytes of metadata-version stamp", - vlen); + debug!("checking {} bytes of metadata-version stamp", vlen); let minsz = cmp::min(vlen, csz); let buf0 = slice::from_raw_parts(cvbuf, minsz); let version_ok = buf0 == METADATA_HEADER; @@ -838,8 +873,7 @@ fn get_metadata_section_imp(target: &Target, flavor: CrateFlavor, filename: &Pat } let cvbuf1 = cvbuf.offset(vlen as isize); - debug!("inflating {} bytes of compressed metadata", - csz - vlen); + debug!("inflating {} bytes of compressed metadata", csz - vlen); let bytes = slice::from_raw_parts(cvbuf1, csz - vlen); match flate::inflate_bytes(bytes) { Ok(inflated) => { @@ -883,14 +917,15 @@ pub fn read_meta_section_name(_target: &Target) -> &'static str { } // A diagnostic function for dumping crate metadata to an output stream -pub fn list_file_metadata(target: &Target, path: &Path, - out: &mut io::Write) -> io::Result<()> { +pub fn list_file_metadata(target: &Target, path: &Path, out: &mut io::Write) -> io::Result<()> { let filename = path.file_name().unwrap().to_str().unwrap(); - let flavor = if filename.ends_with(".rlib") { CrateFlavor::Rlib } else { CrateFlavor::Dylib }; + let flavor = if filename.ends_with(".rlib") { + CrateFlavor::Rlib + } else { + CrateFlavor::Dylib + }; match get_metadata_section(target, flavor, path) { Ok(metadata) => metadata.list_crate_metadata(out), - Err(msg) => { - write!(out, "{}\n", msg) - } + Err(msg) => write!(out, "{}\n", msg), } } diff --git a/src/librustc_metadata/macro_import.rs b/src/librustc_metadata/macro_import.rs deleted file mode 100644 index 2ff7a6c41b..0000000000 --- a/src/librustc_metadata/macro_import.rs +++ /dev/null @@ -1,219 +0,0 @@ -// 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. - -//! Used by `rustc` when loading a crate with exported macros. - -use std::collections::HashSet; -use std::rc::Rc; -use std::env; -use std::mem; - -use creader::{CrateLoader, Macros}; - -use rustc::hir::def_id::DefIndex; -use rustc::middle::cstore::LoadedMacro; -use rustc::session::Session; -use rustc::util::nodemap::FnvHashMap; -use rustc_back::dynamic_lib::DynamicLibrary; -use rustc_macro::TokenStream; -use rustc_macro::__internal::Registry; -use syntax::ast; -use syntax::attr; -use syntax::parse::token; -use syntax_ext::deriving::custom::CustomDerive; -use syntax_pos::Span; - -pub fn call_bad_macro_reexport(a: &Session, b: Span) { - span_err!(a, b, E0467, "bad macro reexport"); -} - -pub type MacroSelection = FnvHashMap; - -pub fn load_macros(loader: &mut CrateLoader, extern_crate: &ast::Item, allows_macros: bool) - -> Vec { - loader.load_crate(extern_crate, allows_macros) -} - -impl<'a> CrateLoader<'a> { - fn load_crate(&mut self, - extern_crate: &ast::Item, - allows_macros: bool) -> Vec { - // Parse the attributes relating to macros. - let mut import = Some(FnvHashMap()); // None => load all - let mut reexport = FnvHashMap(); - - for attr in &extern_crate.attrs { - let mut used = true; - match &attr.name()[..] { - "macro_use" => { - let names = attr.meta_item_list(); - if names.is_none() { - // no names => load all - import = None; - } - if let (Some(sel), Some(names)) = (import.as_mut(), names) { - for attr in names { - if let Some(word) = attr.word() { - sel.insert(word.name().clone(), attr.span()); - } else { - span_err!(self.sess, attr.span(), E0466, "bad macro import"); - } - } - } - } - "macro_reexport" => { - let names = match attr.meta_item_list() { - Some(names) => names, - None => { - call_bad_macro_reexport(self.sess, attr.span); - continue; - } - }; - - for attr in names { - if let Some(word) = attr.word() { - reexport.insert(word.name().clone(), attr.span()); - } else { - call_bad_macro_reexport(self.sess, attr.span()); - } - } - } - _ => used = false, - } - if used { - attr::mark_used(attr); - } - } - - self.load_macros(extern_crate, allows_macros, import, reexport) - } - - fn load_macros<'b>(&mut self, - vi: &ast::Item, - allows_macros: bool, - import: Option, - reexport: MacroSelection) - -> Vec { - if let Some(sel) = import.as_ref() { - if sel.is_empty() && reexport.is_empty() { - return Vec::new(); - } - } - - if !allows_macros { - span_err!(self.sess, vi.span, E0468, - "an `extern crate` loading macros must be at the crate root"); - return Vec::new(); - } - - let mut macros = self.creader.read_macros(vi); - let mut ret = Vec::new(); - let mut seen = HashSet::new(); - - for mut def in macros.macro_rules.drain(..) { - let name = def.ident.name.as_str(); - - def.use_locally = match import.as_ref() { - None => true, - Some(sel) => sel.contains_key(&name), - }; - def.export = reexport.contains_key(&name); - def.allow_internal_unstable = attr::contains_name(&def.attrs, - "allow_internal_unstable"); - debug!("load_macros: loaded: {:?}", def); - ret.push(LoadedMacro::Def(def)); - seen.insert(name); - } - - if let Some(index) = macros.custom_derive_registrar { - // custom derive crates currently should not have any macro_rules! - // exported macros, enforced elsewhere - assert_eq!(ret.len(), 0); - - if import.is_some() { - self.sess.span_err(vi.span, "`rustc-macro` crates cannot be \ - selectively imported from, must \ - use `#[macro_use]`"); - } - - if reexport.len() > 0 { - self.sess.span_err(vi.span, "`rustc-macro` crates cannot be \ - reexported from"); - } - - self.load_derive_macros(vi.span, ¯os, index, &mut ret); - } - - if let Some(sel) = import.as_ref() { - for (name, span) in sel { - if !seen.contains(&name) { - span_err!(self.sess, *span, E0469, - "imported macro not found"); - } - } - } - - for (name, span) in &reexport { - if !seen.contains(&name) { - span_err!(self.sess, *span, E0470, - "reexported macro not found"); - } - } - - return ret - } - - /// Load the custom derive macros into the list of macros we're loading. - /// - /// Note that this is intentionally similar to how we load plugins today, - /// but also intentionally separate. Plugins are likely always going to be - /// implemented as dynamic libraries, but we have a possible future where - /// custom derive (and other macro-1.1 style features) are implemented via - /// executables and custom IPC. - fn load_derive_macros(&mut self, - span: Span, - macros: &Macros, - index: DefIndex, - ret: &mut Vec) { - // Make sure the path contains a / or the linker will search for it. - let path = macros.dylib.as_ref().unwrap(); - let path = env::current_dir().unwrap().join(path); - let lib = match DynamicLibrary::open(Some(&path)) { - Ok(lib) => lib, - Err(err) => self.sess.span_fatal(span, &err), - }; - - let sym = self.sess.generate_derive_registrar_symbol(¯os.svh, index); - let registrar = unsafe { - let sym = match lib.symbol(&sym) { - Ok(f) => f, - Err(err) => self.sess.span_fatal(span, &err), - }; - mem::transmute::<*mut u8, fn(&mut Registry)>(sym) - }; - - struct MyRegistrar<'a>(&'a mut Vec); - - impl<'a> Registry for MyRegistrar<'a> { - fn register_custom_derive(&mut self, - trait_name: &str, - expand: fn(TokenStream) -> TokenStream) { - let derive = Rc::new(CustomDerive::new(expand)); - self.0.push(LoadedMacro::CustomDerive(trait_name.to_string(), derive)); - } - } - - registrar(&mut MyRegistrar(ret)); - - // Intentionally leak the dynamic library. We can't ever unload it - // since the library can make things that will live arbitrarily long. - mem::forget(lib); - } -} diff --git a/src/librustc_metadata/schema.rs b/src/librustc_metadata/schema.rs index f4d1e8e17f..3d1bd77d8b 100644 --- a/src/librustc_metadata/schema.rs +++ b/src/librustc_metadata/schema.rs @@ -12,13 +12,13 @@ use astencode; use index; use rustc::hir; -use rustc::hir::def; +use rustc::hir::def::{self, CtorKind}; use rustc::hir::def_id::{DefIndex, DefId}; use rustc::middle::cstore::{LinkagePreference, NativeLibraryKind}; use rustc::middle::lang_items; use rustc::mir; use rustc::ty::{self, Ty}; -use rustc::session::config::PanicStrategy; +use rustc_back::PanicStrategy; use rustc_serialize as serialize; use syntax::{ast, attr}; @@ -26,11 +26,10 @@ use syntax_pos::{self, Span}; use std::marker::PhantomData; -#[cfg(not(test))] -pub const RUSTC_VERSION: &'static str = concat!("rustc ", env!("CFG_VERSION")); - -#[cfg(test)] -pub const RUSTC_VERSION: &'static str = "rustc 0.0.0-unit-test"; +pub fn rustc_version() -> String { + format!("rustc {}", + option_env!("CFG_VERSION").unwrap_or("unknown version")) +} /// Metadata encoding version. /// NB: increment this if you change the format of metadata such that @@ -43,11 +42,8 @@ pub const METADATA_VERSION: u8 = 3; /// as a length of 0 by old compilers. /// /// This header is followed by the position of the `CrateRoot`. -pub const METADATA_HEADER: &'static [u8; 12] = &[ - 0, 0, 0, 0, - b'r', b'u', b's', b't', - 0, 0, 0, METADATA_VERSION -]; +pub const METADATA_HEADER: &'static [u8; 12] = + &[0, 0, 0, 0, b'r', b'u', b's', b't', 0, 0, 0, METADATA_VERSION]; /// The shorthand encoding uses an enum's variant index `usize` /// and is offset by this value so it never matches a real variant. @@ -72,14 +68,14 @@ pub const SHORTHAND_OFFSET: usize = 0x80; #[must_use] pub struct Lazy { pub position: usize, - _marker: PhantomData + _marker: PhantomData, } impl Lazy { pub fn with_position(position: usize) -> Lazy { Lazy { position: position, - _marker: PhantomData + _marker: PhantomData, } } @@ -92,7 +88,9 @@ impl Lazy { impl Copy for Lazy {} impl Clone for Lazy { - fn clone(&self) -> Self { *self } + fn clone(&self) -> Self { + *self + } } impl serialize::UseSpecializedEncodable for Lazy {} @@ -114,7 +112,7 @@ impl serialize::UseSpecializedDecodable for Lazy {} pub struct LazySeq { pub len: usize, pub position: usize, - _marker: PhantomData + _marker: PhantomData, } impl LazySeq { @@ -126,7 +124,7 @@ impl LazySeq { LazySeq { len: len, position: position, - _marker: PhantomData + _marker: PhantomData, } } @@ -138,7 +136,9 @@ impl LazySeq { impl Copy for LazySeq {} impl Clone for LazySeq { - fn clone(&self) -> Self { *self } + fn clone(&self) -> Self { + *self + } } impl serialize::UseSpecializedEncodable for LazySeq {} @@ -157,7 +157,7 @@ pub enum LazyState { /// Inside a metadata node, with a previous `Lazy` or `LazySeq`. /// The position is a conservative estimate of where that /// previous `Lazy` / `LazySeq` would end (see their comments). - Previous(usize) + Previous(usize), } #[derive(RustcEncodable, RustcDecodable)] @@ -187,13 +187,13 @@ pub struct CrateRoot { pub struct CrateDep { pub name: ast::Name, pub hash: hir::svh::Svh, - pub explicitly_linked: bool + pub explicitly_linked: bool, } #[derive(RustcEncodable, RustcDecodable)] pub struct TraitImpls { pub trait_id: (u32, DefIndex), - pub impls: LazySeq + pub impls: LazySeq, } #[derive(RustcEncodable, RustcDecodable)] @@ -201,7 +201,7 @@ pub struct MacroDef { pub name: ast::Name, pub attrs: Vec, pub span: Span, - pub body: String + pub body: String, } #[derive(RustcEncodable, RustcDecodable)] @@ -221,7 +221,7 @@ pub struct Entry<'tcx> { pub predicates: Option>>, pub ast: Option>>, - pub mir: Option>> + pub mir: Option>>, } #[derive(Copy, Clone, RustcEncodable, RustcDecodable)] @@ -247,28 +247,28 @@ pub enum EntryKind<'tcx> { DefaultImpl(Lazy>), Method(Lazy>), AssociatedType(AssociatedContainer), - AssociatedConst(AssociatedContainer) + AssociatedConst(AssociatedContainer), } #[derive(RustcEncodable, RustcDecodable)] pub struct ModData { - pub reexports: LazySeq + pub reexports: LazySeq, } #[derive(RustcEncodable, RustcDecodable)] pub struct FnData { pub constness: hir::Constness, - pub arg_names: LazySeq + pub arg_names: LazySeq, } #[derive(RustcEncodable, RustcDecodable)] pub struct VariantData { - pub kind: ty::VariantKind, + pub ctor_kind: CtorKind, pub disr: u64, /// If this is a struct's only variant, this /// is the index of the "struct ctor" item. - pub struct_ctor: Option + pub struct_ctor: Option, } #[derive(RustcEncodable, RustcDecodable)] @@ -277,7 +277,7 @@ pub struct TraitData<'tcx> { pub paren_sugar: bool, pub has_default_impl: bool, pub trait_ref: Lazy>, - pub super_predicates: Lazy> + pub super_predicates: Lazy>, } #[derive(RustcEncodable, RustcDecodable)] @@ -285,7 +285,7 @@ pub struct ImplData<'tcx> { pub polarity: hir::ImplPolarity, pub parent_impl: Option, pub coerce_unsized_kind: Option, - pub trait_ref: Option>> + pub trait_ref: Option>>, } /// Describes whether the container of an associated item @@ -296,21 +296,17 @@ pub enum AssociatedContainer { TraitRequired, TraitWithDefault, ImplDefault, - ImplFinal + ImplFinal, } impl AssociatedContainer { pub fn with_def_id(&self, def_id: DefId) -> ty::ImplOrTraitItemContainer { match *self { AssociatedContainer::TraitRequired | - AssociatedContainer::TraitWithDefault => { - ty::TraitContainer(def_id) - } + AssociatedContainer::TraitWithDefault => ty::TraitContainer(def_id), AssociatedContainer::ImplDefault | - AssociatedContainer::ImplFinal => { - ty::ImplContainer(def_id) - } + AssociatedContainer::ImplFinal => ty::ImplContainer(def_id), } } @@ -320,7 +316,7 @@ impl AssociatedContainer { AssociatedContainer::TraitWithDefault | AssociatedContainer::ImplDefault | - AssociatedContainer::ImplFinal => true + AssociatedContainer::ImplFinal => true, } } @@ -330,7 +326,7 @@ impl AssociatedContainer { AssociatedContainer::TraitWithDefault | AssociatedContainer::ImplDefault => hir::Defaultness::Default, - AssociatedContainer::ImplFinal => hir::Defaultness::Final + AssociatedContainer::ImplFinal => hir::Defaultness::Final, } } } @@ -339,11 +335,11 @@ impl AssociatedContainer { pub struct MethodData<'tcx> { pub fn_data: FnData, pub container: AssociatedContainer, - pub explicit_self: Lazy> + pub explicit_self: Lazy>, } #[derive(RustcEncodable, RustcDecodable)] pub struct ClosureData<'tcx> { pub kind: ty::ClosureKind, - pub ty: Lazy> + pub ty: Lazy>, } diff --git a/src/librustc_mir/build/block.rs b/src/librustc_mir/build/block.rs index 34d7973264..b53f8c4da8 100644 --- a/src/librustc_mir/build/block.rs +++ b/src/librustc_mir/build/block.rs @@ -10,7 +10,7 @@ use build::{BlockAnd, BlockAndExtension, Builder}; use hair::*; -use rustc::mir::repr::*; +use rustc::mir::*; use rustc::hir; impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> { diff --git a/src/librustc_mir/build/cfg.rs b/src/librustc_mir/build/cfg.rs index 026a79b32b..9f612175e5 100644 --- a/src/librustc_mir/build/cfg.rs +++ b/src/librustc_mir/build/cfg.rs @@ -14,7 +14,7 @@ //! Routines for manipulating the control-flow graph. use build::CFG; -use rustc::mir::repr::*; +use rustc::mir::*; impl<'tcx> CFG<'tcx> { pub fn block_data(&self, blk: BasicBlock) -> &BasicBlockData<'tcx> { diff --git a/src/librustc_mir/build/expr/as_constant.rs b/src/librustc_mir/build/expr/as_constant.rs index a08d14d9e2..6230123a9c 100644 --- a/src/librustc_mir/build/expr/as_constant.rs +++ b/src/librustc_mir/build/expr/as_constant.rs @@ -12,7 +12,7 @@ use build::Builder; use hair::*; -use rustc::mir::repr::*; +use rustc::mir::*; impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> { /// Compile `expr`, yielding a compile-time constant. Assumes that diff --git a/src/librustc_mir/build/expr/as_lvalue.rs b/src/librustc_mir/build/expr/as_lvalue.rs index 78330f0b97..58abaa0c48 100644 --- a/src/librustc_mir/build/expr/as_lvalue.rs +++ b/src/librustc_mir/build/expr/as_lvalue.rs @@ -13,7 +13,7 @@ use build::{BlockAnd, BlockAndExtension, Builder}; use build::expr::category::Category; use hair::*; -use rustc::mir::repr::*; +use rustc::mir::*; use rustc_data_structures::indexed_vec::Idx; @@ -77,11 +77,11 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> { success.and(slice.index(idx)) } ExprKind::SelfRef => { - block.and(Lvalue::Arg(Arg::new(0))) + block.and(Lvalue::Local(Local::new(1))) } ExprKind::VarRef { id } => { let index = this.var_indices[&id]; - block.and(Lvalue::Var(index)) + block.and(Lvalue::Local(index)) } ExprKind::StaticRef { id } => { block.and(Lvalue::Static(id)) diff --git a/src/librustc_mir/build/expr/as_operand.rs b/src/librustc_mir/build/expr/as_operand.rs index beb9ca256a..09cdcc74ef 100644 --- a/src/librustc_mir/build/expr/as_operand.rs +++ b/src/librustc_mir/build/expr/as_operand.rs @@ -13,7 +13,7 @@ use build::{BlockAnd, BlockAndExtension, Builder}; use build::expr::category::Category; use hair::*; -use rustc::mir::repr::*; +use rustc::mir::*; impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> { /// Compile `expr` into a value that can be used as an operand. diff --git a/src/librustc_mir/build/expr/as_rvalue.rs b/src/librustc_mir/build/expr/as_rvalue.rs index 61375a3610..490f675c3d 100644 --- a/src/librustc_mir/build/expr/as_rvalue.rs +++ b/src/librustc_mir/build/expr/as_rvalue.rs @@ -22,7 +22,7 @@ use hair::*; use rustc_const_math::{ConstInt, ConstIsize}; use rustc::middle::const_val::ConstVal; use rustc::ty; -use rustc::mir::repr::*; +use rustc::mir::*; use syntax::ast; use syntax_pos::Span; @@ -164,7 +164,7 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> { .map(|f| unpack!(block = this.as_operand(block, f))) .collect(); - block.and(Rvalue::Aggregate(AggregateKind::Vec, fields)) + block.and(Rvalue::Aggregate(AggregateKind::Array, fields)) } ExprKind::Tuple { fields } => { // see (*) above // first process the set of fields @@ -257,7 +257,7 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> { let source_info = self.source_info(span); let bool_ty = self.hir.bool_ty(); if self.hir.check_overflow() && op.is_checkable() && ty.is_integral() { - let result_tup = self.hir.tcx().mk_tup(vec![ty, bool_ty]); + let result_tup = self.hir.tcx().intern_tup(&[ty, bool_ty]); let result_value = self.temp(result_tup); self.cfg.push_assign(block, source_info, diff --git a/src/librustc_mir/build/expr/as_temp.rs b/src/librustc_mir/build/expr/as_temp.rs index 85128cbbba..fb12e08aff 100644 --- a/src/librustc_mir/build/expr/as_temp.rs +++ b/src/librustc_mir/build/expr/as_temp.rs @@ -13,7 +13,7 @@ use build::{BlockAnd, BlockAndExtension, Builder}; use build::expr::category::Category; use hair::*; -use rustc::mir::repr::*; +use rustc::mir::*; impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> { /// Compile `expr` into a fresh temporary. This is used when building diff --git a/src/librustc_mir/build/expr/into.rs b/src/librustc_mir/build/expr/into.rs index 58265b5b0d..5fa0844222 100644 --- a/src/librustc_mir/build/expr/into.rs +++ b/src/librustc_mir/build/expr/into.rs @@ -14,7 +14,7 @@ use build::{BlockAnd, BlockAndExtension, Builder}; use build::expr::category::{Category, RvalueFunc}; use hair::*; use rustc::ty; -use rustc::mir::repr::*; +use rustc::mir::*; impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> { /// Compile `expr`, storing the result into `destination`, which diff --git a/src/librustc_mir/build/expr/stmt.rs b/src/librustc_mir/build/expr/stmt.rs index 8ae23c9103..4a1926e7c5 100644 --- a/src/librustc_mir/build/expr/stmt.rs +++ b/src/librustc_mir/build/expr/stmt.rs @@ -12,7 +12,7 @@ use build::{BlockAnd, BlockAndExtension, Builder}; use build::scope::LoopScope; use hair::*; use rustc::middle::region::CodeExtent; -use rustc::mir::repr::*; +use rustc::mir::*; use syntax_pos::Span; impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> { @@ -90,9 +90,13 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> { } ExprKind::Return { value } => { block = match value { - Some(value) => unpack!(this.into(&Lvalue::ReturnPointer, block, value)), + Some(value) => { + unpack!(this.into(&Lvalue::Local(RETURN_POINTER), block, value)) + } None => { - this.cfg.push_assign_unit(block, source_info, &Lvalue::ReturnPointer); + this.cfg.push_assign_unit(block, + source_info, + &Lvalue::Local(RETURN_POINTER)); block } }; diff --git a/src/librustc_mir/build/into.rs b/src/librustc_mir/build/into.rs index 17ccb701c2..5c133780e4 100644 --- a/src/librustc_mir/build/into.rs +++ b/src/librustc_mir/build/into.rs @@ -16,7 +16,7 @@ use build::{BlockAnd, Builder}; use hair::*; -use rustc::mir::repr::*; +use rustc::mir::*; pub trait EvalInto<'tcx> { fn eval_into<'a, 'gcx>(self, diff --git a/src/librustc_mir/build/matches/mod.rs b/src/librustc_mir/build/matches/mod.rs index 1b64b4d0b5..727e634ef9 100644 --- a/src/librustc_mir/build/matches/mod.rs +++ b/src/librustc_mir/build/matches/mod.rs @@ -18,7 +18,7 @@ use rustc_data_structures::fnv::FnvHashMap; use rustc_data_structures::bitvec::BitVector; use rustc::middle::const_val::ConstVal; use rustc::ty::{AdtDef, Ty}; -use rustc::mir::repr::*; +use rustc::mir::*; use hair::*; use syntax::ast::{Name, NodeId}; use syntax_pos::Span; @@ -123,7 +123,7 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> { var, subpattern: None, .. } => { self.storage_live_for_bindings(block, &irrefutable_pat); - let lvalue = Lvalue::Var(self.var_indices[&var]); + let lvalue = Lvalue::Local(self.var_indices[&var]); return self.into(&lvalue, block, initializer); } _ => {} @@ -214,7 +214,7 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> { pattern: &Pattern<'tcx>) { match *pattern.kind { PatternKind::Binding { var, ref subpattern, .. } => { - let lvalue = Lvalue::Var(self.var_indices[&var]); + let lvalue = Lvalue::Local(self.var_indices[&var]); let source_info = self.source_info(pattern.span); self.cfg.push(block, Statement { source_info: source_info, @@ -705,10 +705,10 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> { let source_info = self.source_info(binding.span); self.cfg.push(block, Statement { source_info: source_info, - kind: StatementKind::StorageLive(Lvalue::Var(var_index)) + kind: StatementKind::StorageLive(Lvalue::Local(var_index)) }); self.cfg.push_assign(block, source_info, - &Lvalue::Var(var_index), rvalue); + &Lvalue::Local(var_index), rvalue); } } @@ -718,19 +718,19 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> { name: Name, var_id: NodeId, var_ty: Ty<'tcx>) - -> Var + -> Local { debug!("declare_binding(var_id={:?}, name={:?}, var_ty={:?}, source_info={:?})", var_id, name, var_ty, source_info); - let var = self.var_decls.push(VarDecl::<'tcx> { - source_info: source_info, + let var = self.local_decls.push(LocalDecl::<'tcx> { mutability: mutability, - name: name, ty: var_ty.clone(), + name: Some(name), + source_info: Some(source_info), }); let extent = self.extent_of_innermost_scope(); - self.schedule_drop(source_info.span, extent, &Lvalue::Var(var), var_ty); + self.schedule_drop(source_info.span, extent, &Lvalue::Local(var), var_ty); self.var_indices.insert(var_id, var); debug!("declare_binding: var={:?}", var); diff --git a/src/librustc_mir/build/matches/simplify.rs b/src/librustc_mir/build/matches/simplify.rs index 8392248e3f..71282dcf0b 100644 --- a/src/librustc_mir/build/matches/simplify.rs +++ b/src/librustc_mir/build/matches/simplify.rs @@ -25,7 +25,7 @@ use build::{BlockAnd, BlockAndExtension, Builder}; use build::matches::{Binding, MatchPair, Candidate}; use hair::*; -use rustc::mir::repr::*; +use rustc::mir::*; use std::mem; diff --git a/src/librustc_mir/build/matches/test.rs b/src/librustc_mir/build/matches/test.rs index bf43bfb326..5984b0f789 100644 --- a/src/librustc_mir/build/matches/test.rs +++ b/src/librustc_mir/build/matches/test.rs @@ -22,7 +22,7 @@ use rustc_data_structures::fnv::FnvHashMap; use rustc_data_structures::bitvec::BitVector; use rustc::middle::const_val::ConstVal; use rustc::ty::{self, Ty}; -use rustc::mir::repr::*; +use rustc::mir::*; use syntax_pos::Span; use std::cmp::Ordering; @@ -73,8 +73,8 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> { Test { span: match_pair.pattern.span, kind: TestKind::Range { - lo: lo.clone(), - hi: hi.clone(), + lo: Literal::Value { value: lo.clone() }, + hi: Literal::Value { value: hi.clone() }, ty: match_pair.pattern.ty.clone(), }, } diff --git a/src/librustc_mir/build/matches/util.rs b/src/librustc_mir/build/matches/util.rs index 53ebf6fceb..a013875b31 100644 --- a/src/librustc_mir/build/matches/util.rs +++ b/src/librustc_mir/build/matches/util.rs @@ -11,7 +11,7 @@ use build::Builder; use build::matches::MatchPair; use hair::*; -use rustc::mir::repr::*; +use rustc::mir::*; use std::u32; impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> { diff --git a/src/librustc_mir/build/misc.rs b/src/librustc_mir/build/misc.rs index 79a4cf7304..a5f51ef35b 100644 --- a/src/librustc_mir/build/misc.rs +++ b/src/librustc_mir/build/misc.rs @@ -17,7 +17,7 @@ use rustc_const_math::{ConstInt, ConstUsize, ConstIsize}; use rustc::middle::const_val::ConstVal; use rustc::ty::{self, Ty}; -use rustc::mir::repr::*; +use rustc::mir::*; use syntax::ast; use syntax_pos::Span; @@ -28,10 +28,10 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> { /// NB: **No cleanup is scheduled for this temporary.** You should /// call `schedule_drop` once the temporary is initialized. pub fn temp(&mut self, ty: Ty<'tcx>) -> Lvalue<'tcx> { - let temp = self.temp_decls.push(TempDecl { ty: ty }); - let lvalue = Lvalue::Temp(temp); + let temp = self.local_decls.push(LocalDecl::new_temp(ty)); + let lvalue = Lvalue::Local(temp); debug!("temp: created temp {:?} with type {:?}", - lvalue, self.temp_decls[temp].ty); + lvalue, self.local_decls[temp].ty); lvalue } diff --git a/src/librustc_mir/build/mod.rs b/src/librustc_mir/build/mod.rs index 23591f05b8..b37dd8dd0a 100644 --- a/src/librustc_mir/build/mod.rs +++ b/src/librustc_mir/build/mod.rs @@ -9,9 +9,11 @@ // except according to those terms. use hair::cx::Cx; +use hair::Pattern; + use rustc::middle::region::{CodeExtent, CodeExtentData, ROOT_CODE_EXTENT}; use rustc::ty::{self, Ty}; -use rustc::mir::repr::*; +use rustc::mir::*; use rustc::util::nodemap::NodeMap; use rustc::hir; use syntax::abi::Abi; @@ -28,6 +30,7 @@ pub struct Builder<'a, 'gcx: 'a+'tcx, 'tcx: 'a> { cfg: CFG<'tcx>, fn_span: Span, + arg_count: usize, /// the current set of scopes, updated as we traverse; /// see the `scope` module for more details @@ -49,9 +52,9 @@ pub struct Builder<'a, 'gcx: 'a+'tcx, 'tcx: 'a> { visibility_scopes: IndexVec, visibility_scope: VisibilityScope, - var_decls: IndexVec>, - var_indices: NodeMap, - temp_decls: IndexVec>, + /// Maps node ids of variable bindings to the `Local`s created for them. + var_indices: NodeMap, + local_decls: IndexVec>, unit_temp: Option>, /// cached block with the RESUME terminator; this is created @@ -157,9 +160,11 @@ pub fn construct_fn<'a, 'gcx, 'tcx, A>(hir: Cx<'a, 'gcx, 'tcx>, -> (Mir<'tcx>, ScopeAuxiliaryVec) where A: Iterator, Option<&'gcx hir::Pat>)> { + let arguments: Vec<_> = arguments.collect(); + let tcx = hir.tcx(); let span = tcx.map.span(fn_id); - let mut builder = Builder::new(hir, span); + let mut builder = Builder::new(hir, span, arguments.len(), return_ty); let body_id = ast_block.id; let call_site_extent = @@ -169,27 +174,27 @@ pub fn construct_fn<'a, 'gcx, 'tcx, A>(hir: Cx<'a, 'gcx, 'tcx>, tcx.region_maps.lookup_code_extent( CodeExtentData::ParameterScope { fn_id: fn_id, body_id: body_id }); let mut block = START_BLOCK; - let mut arg_decls = unpack!(block = builder.in_scope(call_site_extent, block, |builder| { - let arg_decls = unpack!(block = builder.in_scope(arg_extent, block, |builder| { - builder.args_and_body(block, return_ty, arguments, arg_extent, ast_block) + unpack!(block = builder.in_scope(call_site_extent, block, |builder| { + unpack!(block = builder.in_scope(arg_extent, block, |builder| { + builder.args_and_body(block, return_ty, &arguments, arg_extent, ast_block) })); - - let source_info = builder.source_info(span); + // Attribute epilogue to function's closing brace + let fn_end = Span { lo: span.hi, ..span }; + let source_info = builder.source_info(fn_end); let return_block = builder.return_block(); builder.cfg.terminate(block, source_info, TerminatorKind::Goto { target: return_block }); builder.cfg.terminate(return_block, source_info, TerminatorKind::Return); - return_block.and(arg_decls) + return_block.unit() })); assert_eq!(block, builder.return_block()); - match tcx.node_id_to_type(fn_id).sty { + let mut spread_arg = None; + match tcx.tables().node_id_to_type(fn_id).sty { ty::TyFnDef(_, _, f) if f.abi == Abi::RustCall => { // RustCall pseudo-ABI untuples the last argument. - if let Some(last_arg) = arg_decls.last() { - arg_decls[last_arg].spread = true; - } + spread_arg = Some(Local::new(arguments.len())); } _ => {} } @@ -198,7 +203,7 @@ pub fn construct_fn<'a, 'gcx, 'tcx, A>(hir: Cx<'a, 'gcx, 'tcx>, let upvar_decls: Vec<_> = tcx.with_freevars(fn_id, |freevars| { freevars.iter().map(|fv| { let var_id = tcx.map.as_local_node_id(fv.def.def_id()).unwrap(); - let by_ref = tcx.upvar_capture(ty::UpvarId { + let by_ref = tcx.tables().upvar_capture(ty::UpvarId { var_id: var_id, closure_expr_id: fn_id }).map_or(false, |capture| match capture { @@ -218,7 +223,9 @@ pub fn construct_fn<'a, 'gcx, 'tcx, A>(hir: Cx<'a, 'gcx, 'tcx>, }).collect() }); - builder.finish(upvar_decls, arg_decls, return_ty) + let (mut mir, aux) = builder.finish(upvar_decls, return_ty); + mir.spread_arg = spread_arg; + (mir, aux) } pub fn construct_const<'a, 'gcx, 'tcx>(hir: Cx<'a, 'gcx, 'tcx>, @@ -226,15 +233,16 @@ pub fn construct_const<'a, 'gcx, 'tcx>(hir: Cx<'a, 'gcx, 'tcx>, ast_expr: &'tcx hir::Expr) -> (Mir<'tcx>, ScopeAuxiliaryVec) { let tcx = hir.tcx(); + let ty = tcx.tables().expr_ty_adjusted(ast_expr); let span = tcx.map.span(item_id); - let mut builder = Builder::new(hir, span); + let mut builder = Builder::new(hir, span, 0, ty); let extent = tcx.region_maps.temporary_scope(ast_expr.id) .unwrap_or(ROOT_CODE_EXTENT); let mut block = START_BLOCK; let _ = builder.in_scope(extent, block, |builder| { let expr = builder.hir.mirror(ast_expr); - unpack!(block = builder.into(&Lvalue::ReturnPointer, block, expr)); + unpack!(block = builder.into(&Lvalue::Local(RETURN_POINTER), block, expr)); let source_info = builder.source_info(span); let return_block = builder.return_block(); @@ -246,23 +254,26 @@ pub fn construct_const<'a, 'gcx, 'tcx>(hir: Cx<'a, 'gcx, 'tcx>, return_block.unit() }); - let ty = tcx.expr_ty_adjusted(ast_expr); - builder.finish(vec![], IndexVec::new(), ty) + builder.finish(vec![], ty) } impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> { - fn new(hir: Cx<'a, 'gcx, 'tcx>, span: Span) -> Builder<'a, 'gcx, 'tcx> { + fn new(hir: Cx<'a, 'gcx, 'tcx>, + span: Span, + arg_count: usize, + return_ty: Ty<'tcx>) + -> Builder<'a, 'gcx, 'tcx> { let mut builder = Builder { hir: hir, cfg: CFG { basic_blocks: IndexVec::new() }, fn_span: span, + arg_count: arg_count, scopes: vec![], visibility_scopes: IndexVec::new(), visibility_scope: ARGUMENT_VISIBILITY_SCOPE, scope_auxiliary: IndexVec::new(), loop_scopes: vec![], - temp_decls: IndexVec::new(), - var_decls: IndexVec::new(), + local_decls: IndexVec::from_elem_n(LocalDecl::new_return_pointer(return_ty), 1), var_indices: NodeMap(), unit_temp: None, cached_resume_block: None, @@ -278,7 +289,6 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> { fn finish(self, upvar_decls: Vec, - arg_decls: IndexVec>, return_ty: Ty<'tcx>) -> (Mir<'tcx>, ScopeAuxiliaryVec) { for (index, block) in self.cfg.basic_blocks.iter().enumerate() { @@ -291,29 +301,47 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> { self.visibility_scopes, IndexVec::new(), return_ty, - self.var_decls, - arg_decls, - self.temp_decls, + self.local_decls, + self.arg_count, upvar_decls, self.fn_span ), self.scope_auxiliary) } - fn args_and_body(&mut self, - mut block: BasicBlock, - return_ty: Ty<'tcx>, - arguments: A, - argument_extent: CodeExtent, - ast_block: &'gcx hir::Block) - -> BlockAnd>> - where A: Iterator, Option<&'gcx hir::Pat>)> + fn args_and_body(&mut self, + mut block: BasicBlock, + return_ty: Ty<'tcx>, + arguments: &[(Ty<'gcx>, Option<&'gcx hir::Pat>)], + argument_extent: CodeExtent, + ast_block: &'gcx hir::Block) + -> BlockAnd<()> { - // to start, translate the argument patterns and collect the argument types. + // Allocate locals for the function arguments + for &(ty, pattern) in arguments.iter() { + // If this is a simple binding pattern, give the local a nice name for debuginfo. + let mut name = None; + if let Some(pat) = pattern { + if let hir::PatKind::Binding(_, ref ident, _) = pat.node { + name = Some(ident.node); + } + } + + self.local_decls.push(LocalDecl { + mutability: Mutability::Not, + ty: ty, + source_info: None, + name: name, + }); + } + let mut scope = None; - let arg_decls = arguments.enumerate().map(|(index, (ty, pattern))| { - let lvalue = Lvalue::Arg(Arg::new(index)); + // Bind the argument patterns + for (index, &(ty, pattern)) in arguments.iter().enumerate() { + // Function arguments always get the first Local indices after the return pointer + let lvalue = Lvalue::Local(Local::new(index + 1)); + if let Some(pattern) = pattern { - let pattern = self.hir.irrefutable_pat(pattern); + let pattern = Pattern::from_hir(self.hir.tcx(), pattern); scope = self.declare_bindings(scope, ast_block.span, &pattern); unpack!(block = self.lvalue_into_pattern(block, pattern, &lvalue)); } @@ -322,19 +350,7 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> { self.schedule_drop(pattern.as_ref().map_or(ast_block.span, |pat| pat.span), argument_extent, &lvalue, ty); - let mut name = keywords::Invalid.name(); - if let Some(pat) = pattern { - if let hir::PatKind::Binding(_, ref ident, _) = pat.node { - name = ident.node; - } - } - - ArgDecl { - ty: ty, - spread: false, - debug_name: name - } - }).collect(); + } // Enter the argument pattern bindings visibility scope, if it exists. if let Some(visibility_scope) = scope { @@ -344,9 +360,10 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> { // FIXME(#32959): temporary hack for the issue at hand let return_is_unit = return_ty.is_nil(); // start the first basic block and translate the body - unpack!(block = self.ast_block(&Lvalue::ReturnPointer, return_is_unit, block, ast_block)); + unpack!(block = self.ast_block(&Lvalue::Local(RETURN_POINTER), + return_is_unit, block, ast_block)); - block.and(arg_decls) + block.unit() } fn get_unit_temp(&mut self) -> Lvalue<'tcx> { diff --git a/src/librustc_mir/build/scope.rs b/src/librustc_mir/build/scope.rs index 0b33e5a145..af8170a1b8 100644 --- a/src/librustc_mir/build/scope.rs +++ b/src/librustc_mir/build/scope.rs @@ -26,7 +26,7 @@ multiple-exit (SEME) region in the control-flow graph. For now, we keep a mapping from each `CodeExtent` to its corresponding SEME region for later reference (see caveat in next paragraph). This is because region scopes are tied to -them. Eventually, when we shift to non-lexical lifetimes, three should +them. Eventually, when we shift to non-lexical lifetimes, there should be no need to remember this mapping. There is one additional wrinkle, actually, that I wanted to hide from @@ -67,7 +67,7 @@ There are numerous "normal" ways to early exit a scope: `break`, early exit occurs, the method `exit_scope` is called. It is given the current point in execution where the early exit occurs, as well as the scope you want to branch to (note that all early exits from to some -other enclosing scope). `exit_scope` will record thid exit point and +other enclosing scope). `exit_scope` will record this exit point and also add all drops. Panics are handled in a similar fashion, except that a panic always @@ -89,15 +89,13 @@ should go to. use build::{BlockAnd, BlockAndExtension, Builder, CFG, ScopeAuxiliary, ScopeId}; use rustc::middle::region::{CodeExtent, CodeExtentData}; use rustc::middle::lang_items; -use rustc::ty::subst::{Kind, Substs, Subst}; +use rustc::ty::subst::{Kind, Subst}; use rustc::ty::{Ty, TyCtxt}; -use rustc::mir::repr::*; +use rustc::mir::*; use syntax_pos::Span; use rustc_data_structures::indexed_vec::Idx; use rustc_data_structures::fnv::FnvHashMap; -use std::iter; - pub struct Scope<'tcx> { /// the scope-id within the scope_auxiliary id: ScopeId, @@ -322,7 +320,11 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> { self.diverge_cleanup(); let scope = self.scopes.pop().unwrap(); assert_eq!(scope.extent, extent); - unpack!(block = build_scope_drops(&mut self.cfg, &scope, &self.scopes, block)); + unpack!(block = build_scope_drops(&mut self.cfg, + &scope, + &self.scopes, + block, + self.arg_count)); self.scope_auxiliary[scope.id] .postdoms .push(self.cfg.current_location(block)); @@ -362,7 +364,11 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> { scope.cached_exits.insert((target, extent), b); b }; - unpack!(block = build_scope_drops(&mut self.cfg, scope, rest, block)); + unpack!(block = build_scope_drops(&mut self.cfg, + scope, + rest, + block, + self.arg_count)); if let Some(ref free_data) = scope.free { let next = self.cfg.start_new_block(); let free = build_free(self.hir.tcx(), &tmp, free_data, next); @@ -454,7 +460,7 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> { } else { // Only temps and vars need their storage dead. match *lvalue { - Lvalue::Temp(_) | Lvalue::Var(_) => DropKind::Storage, + Lvalue::Local(index) if index.index() > self.arg_count => DropKind::Storage, _ => return } }; @@ -513,8 +519,12 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> { if let DropKind::Value { .. } = drop_kind { scope.needs_cleanup = true; } + let tcx = self.hir.tcx(); + let extent_span = extent.span(&tcx.region_maps, &tcx.map).unwrap(); + // Attribute scope exit drops to scope's closing brace + let scope_end = Span { lo: extent_span.hi, .. extent_span}; scope.drops.push(DropData { - span: span, + span: scope_end, location: lvalue.clone(), kind: drop_kind }); @@ -671,7 +681,8 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> { fn build_scope_drops<'tcx>(cfg: &mut CFG<'tcx>, scope: &Scope<'tcx>, earlier_scopes: &[Scope<'tcx>], - mut block: BasicBlock) + mut block: BasicBlock, + arg_count: usize) -> BlockAnd<()> { let mut iter = scope.drops.iter().rev().peekable(); while let Some(drop_data) = iter.next() { @@ -703,7 +714,7 @@ fn build_scope_drops<'tcx>(cfg: &mut CFG<'tcx>, DropKind::Storage => { // Only temps and vars need their storage dead. match drop_data.location { - Lvalue::Temp(_) | Lvalue::Var(_) => {} + Lvalue::Local(index) if index.index() > arg_count => {} _ => continue } @@ -791,7 +802,7 @@ fn build_free<'a, 'gcx, 'tcx>(tcx: TyCtxt<'a, 'gcx, 'tcx>, -> TerminatorKind<'tcx> { let free_func = tcx.lang_items.require(lang_items::BoxFreeFnLangItem) .unwrap_or_else(|e| tcx.sess.fatal(&e)); - let substs = Substs::new(tcx, iter::once(Kind::from(data.item_ty))); + let substs = tcx.intern_substs(&[Kind::from(data.item_ty)]); TerminatorKind::Call { func: Operand::Constant(Constant { span: data.span, diff --git a/src/librustc_mir/def_use.rs b/src/librustc_mir/def_use.rs index 11b4441c84..d20d50c561 100644 --- a/src/librustc_mir/def_use.rs +++ b/src/librustc_mir/def_use.rs @@ -10,15 +10,14 @@ //! Def-use analysis. -use rustc::mir::repr::{Local, Location, Lvalue, Mir}; +use rustc::mir::{Local, Location, Lvalue, Mir}; use rustc::mir::visit::{LvalueContext, MutVisitor, Visitor}; -use rustc_data_structures::indexed_vec::{Idx, IndexVec}; +use rustc_data_structures::indexed_vec::IndexVec; use std::marker::PhantomData; use std::mem; pub struct DefUseAnalysis<'tcx> { info: IndexVec>, - mir_summary: MirSummary, } #[derive(Clone)] @@ -35,15 +34,13 @@ pub struct Use<'tcx> { impl<'tcx> DefUseAnalysis<'tcx> { pub fn new(mir: &Mir<'tcx>) -> DefUseAnalysis<'tcx> { DefUseAnalysis { - info: IndexVec::from_elem_n(Info::new(), mir.count_locals()), - mir_summary: MirSummary::new(mir), + info: IndexVec::from_elem_n(Info::new(), mir.local_decls.len()), } } pub fn analyze(&mut self, mir: &Mir<'tcx>) { let mut finder = DefUseFinder { info: mem::replace(&mut self.info, IndexVec::new()), - mir_summary: self.mir_summary, }; finder.visit_mir(mir); self.info = finder.info @@ -64,7 +61,6 @@ impl<'tcx> DefUseAnalysis<'tcx> { for lvalue_use in &self.info[local].defs_and_uses { MutateUseVisitor::new(local, &mut callback, - self.mir_summary, mir).visit_location(mir, lvalue_use.location) } } @@ -80,13 +76,17 @@ impl<'tcx> DefUseAnalysis<'tcx> { struct DefUseFinder<'tcx> { info: IndexVec>, - mir_summary: MirSummary, } impl<'tcx> DefUseFinder<'tcx> { fn lvalue_mut_info(&mut self, lvalue: &Lvalue<'tcx>) -> Option<&mut Info<'tcx>> { let info = &mut self.info; - self.mir_summary.local_index(lvalue).map(move |local| &mut info[local]) + + if let Lvalue::Local(local) = *lvalue { + Some(&mut info[local]) + } else { + None + } } } @@ -132,18 +132,16 @@ impl<'tcx> Info<'tcx> { struct MutateUseVisitor<'tcx, F> { query: Local, callback: F, - mir_summary: MirSummary, phantom: PhantomData<&'tcx ()>, } impl<'tcx, F> MutateUseVisitor<'tcx, F> { - fn new(query: Local, callback: F, mir_summary: MirSummary, _: &Mir<'tcx>) + fn new(query: Local, callback: F, _: &Mir<'tcx>) -> MutateUseVisitor<'tcx, F> where F: for<'a> FnMut(&'a mut Lvalue<'tcx>, LvalueContext<'tcx>, Location) { MutateUseVisitor { query: query, callback: callback, - mir_summary: mir_summary, phantom: PhantomData, } } @@ -155,43 +153,11 @@ impl<'tcx, F> MutVisitor<'tcx> for MutateUseVisitor<'tcx, F> lvalue: &mut Lvalue<'tcx>, context: LvalueContext<'tcx>, location: Location) { - if self.mir_summary.local_index(lvalue) == Some(self.query) { - (self.callback)(lvalue, context, location) - } - self.super_lvalue(lvalue, context, location) - } -} - -/// A small structure that enables various metadata of the MIR to be queried -/// without a reference to the MIR itself. -#[derive(Clone, Copy)] -pub struct MirSummary { - arg_count: usize, - var_count: usize, - temp_count: usize, -} - -impl MirSummary { - pub fn new(mir: &Mir) -> MirSummary { - MirSummary { - arg_count: mir.arg_decls.len(), - var_count: mir.var_decls.len(), - temp_count: mir.temp_decls.len(), - } - } - - pub fn local_index<'tcx>(&self, lvalue: &Lvalue<'tcx>) -> Option { - match *lvalue { - Lvalue::Arg(arg) => Some(Local::new(arg.index())), - Lvalue::Var(var) => Some(Local::new(var.index() + self.arg_count)), - Lvalue::Temp(temp) => { - Some(Local::new(temp.index() + self.arg_count + self.var_count)) + if let Lvalue::Local(local) = *lvalue { + if local == self.query { + (self.callback)(lvalue, context, location) } - Lvalue::ReturnPointer => { - Some(Local::new(self.arg_count + self.var_count + self.temp_count)) - } - _ => None, } + self.super_lvalue(lvalue, context, location) } } - diff --git a/src/librustc_mir/graphviz.rs b/src/librustc_mir/graphviz.rs index 72b6d7f0e5..dd4dd4699d 100644 --- a/src/librustc_mir/graphviz.rs +++ b/src/librustc_mir/graphviz.rs @@ -10,8 +10,7 @@ use dot; use rustc::hir::def_id::DefId; -use rustc::mir::repr::*; -use rustc::mir::mir_map::MirMap; +use rustc::mir::*; use rustc::ty::TyCtxt; use std::fmt::Debug; use std::io::{self, Write}; @@ -22,14 +21,13 @@ use rustc_data_structures::indexed_vec::Idx; /// Write a graphviz DOT graph of a list of MIRs. pub fn write_mir_graphviz<'a, 'b, 'tcx, W, I>(tcx: TyCtxt<'b, 'tcx, 'tcx>, iter: I, - mir_map: &MirMap<'tcx>, w: &mut W) -> io::Result<()> where W: Write, I: Iterator { for def_id in iter { let nodeid = tcx.map.as_local_node_id(def_id).unwrap(); - let mir = &mir_map.map[&def_id]; + let mir = &tcx.item_mir(def_id); writeln!(w, "digraph Mir_{} {{", nodeid)?; @@ -136,30 +134,31 @@ fn write_graph_label<'a, 'tcx, W: Write>(tcx: TyCtxt<'a, 'tcx, 'tcx>, write!(w, " label= 0 { write!(w, ", ")?; } - write!(w, "{:?}: {}", Lvalue::Arg(Arg::new(i)), escape(&arg.ty))?; + write!(w, "{:?}: {}", Lvalue::Local(arg), escape(&mir.local_decls[arg].ty))?; } write!(w, ") -> {}", escape(mir.return_ty))?; write!(w, r#"
"#)?; - // User variable types (including the user's name in a comment). - for (i, var) in mir.var_decls.iter().enumerate() { + for local in mir.vars_and_temps_iter() { + let decl = &mir.local_decls[local]; + write!(w, "let ")?; - if var.mutability == Mutability::Mut { + if decl.mutability == Mutability::Mut { write!(w, "mut ")?; } - write!(w, r#"{:?}: {}; // {}
"#, - Lvalue::Var(Var::new(i)), escape(&var.ty), var.name)?; - } - // Compiler-introduced temporary types. - for (i, temp) in mir.temp_decls.iter().enumerate() { - write!(w, r#"let mut {:?}: {};
"#, - Lvalue::Temp(Temp::new(i)), escape(&temp.ty))?; + if let Some(name) = decl.name { + write!(w, r#"{:?}: {}; // {}
"#, + Lvalue::Local(local), escape(&decl.ty), name)?; + } else { + write!(w, r#"let mut {:?}: {};
"#, + Lvalue::Local(local), escape(&decl.ty))?; + } } writeln!(w, ">;") diff --git a/src/librustc_mir/hair/cx/block.rs b/src/librustc_mir/hair/cx/block.rs index 52d54f2cc8..cb69de2cb3 100644 --- a/src/librustc_mir/hair/cx/block.rs +++ b/src/librustc_mir/hair/cx/block.rs @@ -57,7 +57,7 @@ fn mirror_stmts<'a, 'gcx, 'tcx>(cx: &mut Cx<'a, 'gcx, 'tcx>, let remainder_extent = cx.tcx.region_maps.lookup_code_extent(remainder_extent); - let pattern = cx.irrefutable_pat(&local.pat); + let pattern = Pattern::from_hir(cx.tcx, &local.pat); result.push(StmtRef::Mirror(Box::new(Stmt { span: stmt.span, kind: StmtKind::Let { @@ -77,7 +77,7 @@ fn mirror_stmts<'a, 'gcx, 'tcx>(cx: &mut Cx<'a, 'gcx, 'tcx>, pub fn to_expr_ref<'a, 'gcx, 'tcx>(cx: &mut Cx<'a, 'gcx, 'tcx>, block: &'tcx hir::Block) -> ExprRef<'tcx> { - let block_ty = cx.tcx.node_id_to_type(block.id); + let block_ty = cx.tcx.tables().node_id_to_type(block.id); let temp_lifetime = cx.tcx.region_maps.temporary_scope(block.id); let expr = Expr { ty: block_ty, diff --git a/src/librustc_mir/hair/cx/expr.rs b/src/librustc_mir/hair/cx/expr.rs index ea7bc99dd0..ba0d3b49a6 100644 --- a/src/librustc_mir/hair/cx/expr.rs +++ b/src/librustc_mir/hair/cx/expr.rs @@ -15,13 +15,13 @@ use hair::cx::Cx; use hair::cx::block; use hair::cx::to_ref::ToRef; use rustc::hir::map; -use rustc::hir::def::Def; +use rustc::hir::def::{Def, CtorKind}; use rustc::middle::const_val::ConstVal; use rustc_const_eval as const_eval; use rustc::middle::region::CodeExtent; use rustc::ty::{self, AdtKind, VariantDef, Ty}; use rustc::ty::cast::CastKind as TyCastKind; -use rustc::mir::repr::*; +use rustc::mir::*; use rustc::hir; use syntax::ptr::P; @@ -35,15 +35,15 @@ impl<'tcx> Mirror<'tcx> for &'tcx hir::Expr { debug!("Expr::make_mirror(): id={}, span={:?}", self.id, self.span); let mut expr = make_mirror_unadjusted(cx, self); + let adj = cx.tcx.tables().adjustments.get(&self.id).cloned(); debug!("make_mirror: unadjusted-expr={:?} applying adjustments={:?}", - expr, cx.tcx.tables.borrow().adjustments.get(&self.id)); + expr, adj); // Now apply adjustments, if any. - match cx.tcx.tables.borrow().adjustments.get(&self.id) { + match adj.map(|adj| (adj.kind, adj.target)) { None => {} - Some(&ty::adjustment::AdjustReifyFnPointer) => { - let adjusted_ty = cx.tcx.expr_ty_adjusted(self); + Some((ty::adjustment::Adjust::ReifyFnPointer, adjusted_ty)) => { expr = Expr { temp_lifetime: temp_lifetime, ty: adjusted_ty, @@ -51,8 +51,7 @@ impl<'tcx> Mirror<'tcx> for &'tcx hir::Expr { kind: ExprKind::ReifyFnPointer { source: expr.to_ref() }, }; } - Some(&ty::adjustment::AdjustUnsafeFnPointer) => { - let adjusted_ty = cx.tcx.expr_ty_adjusted(self); + Some((ty::adjustment::Adjust::UnsafeFnPointer, adjusted_ty)) => { expr = Expr { temp_lifetime: temp_lifetime, ty: adjusted_ty, @@ -60,7 +59,7 @@ impl<'tcx> Mirror<'tcx> for &'tcx hir::Expr { kind: ExprKind::UnsafeFnPointer { source: expr.to_ref() }, }; } - Some(&ty::adjustment::AdjustNeverToAny(adjusted_ty)) => { + Some((ty::adjustment::Adjust::NeverToAny, adjusted_ty)) => { expr = Expr { temp_lifetime: temp_lifetime, ty: adjusted_ty, @@ -68,8 +67,7 @@ impl<'tcx> Mirror<'tcx> for &'tcx hir::Expr { kind: ExprKind::NeverToAny { source: expr.to_ref() }, }; } - Some(&ty::adjustment::AdjustMutToConstPointer) => { - let adjusted_ty = cx.tcx.expr_ty_adjusted(self); + Some((ty::adjustment::Adjust::MutToConstPointer, adjusted_ty)) => { expr = Expr { temp_lifetime: temp_lifetime, ty: adjusted_ty, @@ -77,8 +75,9 @@ impl<'tcx> Mirror<'tcx> for &'tcx hir::Expr { kind: ExprKind::Cast { source: expr.to_ref() }, }; } - Some(&ty::adjustment::AdjustDerefRef(ref adj)) => { - for i in 0..adj.autoderefs { + Some((ty::adjustment::Adjust::DerefRef { autoderefs, autoref, unsize }, + adjusted_ty)) => { + for i in 0..autoderefs { let i = i as u32; let adjusted_ty = expr.ty.adjust_for_autoderef( @@ -86,11 +85,11 @@ impl<'tcx> Mirror<'tcx> for &'tcx hir::Expr { self.id, self.span, i, - |mc| cx.tcx.tables.borrow().method_map.get(&mc).map(|m| m.ty)); + |mc| cx.tcx.tables().method_map.get(&mc).map(|m| m.ty)); debug!("make_mirror: autoderef #{}, adjusted_ty={:?}", i, adjusted_ty); let method_key = ty::MethodCall::autoderef(self.id, i); let meth_ty = - cx.tcx.tables.borrow().method_map.get(&method_key).map(|m| m.ty); + cx.tcx.tables().method_map.get(&method_key).map(|m| m.ty); let kind = if let Some(meth_ty) = meth_ty { debug!("make_mirror: overloaded autoderef (meth_ty={:?})", meth_ty); @@ -128,10 +127,10 @@ impl<'tcx> Mirror<'tcx> for &'tcx hir::Expr { }; } - if let Some(autoref) = adj.autoref { + if let Some(autoref) = autoref { let adjusted_ty = expr.ty.adjust_for_autoref(cx.tcx, Some(autoref)); match autoref { - ty::adjustment::AutoPtr(r, m) => { + ty::adjustment::AutoBorrow::Ref(r, m) => { expr = Expr { temp_lifetime: temp_lifetime, ty: adjusted_ty, @@ -143,7 +142,7 @@ impl<'tcx> Mirror<'tcx> for &'tcx hir::Expr { }, }; } - ty::adjustment::AutoUnsafe(m) => { + ty::adjustment::AutoBorrow::RawPtr(m) => { // Convert this to a suitable `&foo` and // then an unsafe coercion. Limit the region to be just this // expression. @@ -169,10 +168,10 @@ impl<'tcx> Mirror<'tcx> for &'tcx hir::Expr { } } - if let Some(target) = adj.unsize { + if unsize { expr = Expr { temp_lifetime: temp_lifetime, - ty: target, + ty: adjusted_ty, span: self.span, kind: ExprKind::Unsize { source: expr.to_ref() }, }; @@ -212,7 +211,7 @@ impl<'tcx> Mirror<'tcx> for &'tcx hir::Expr { fn make_mirror_unadjusted<'a, 'gcx, 'tcx>(cx: &mut Cx<'a, 'gcx, 'tcx>, expr: &'tcx hir::Expr) -> Expr<'tcx> { - let expr_ty = cx.tcx.expr_ty(expr); + let expr_ty = cx.tcx.tables().expr_ty(expr); let temp_lifetime = cx.tcx.region_maps.temporary_scope(expr.id); let kind = match expr.node { @@ -231,7 +230,7 @@ fn make_mirror_unadjusted<'a, 'gcx, 'tcx>(cx: &mut Cx<'a, 'gcx, 'tcx>, } hir::ExprCall(ref fun, ref args) => { - if cx.tcx.is_method_call(expr.id) { + if cx.tcx.tables().is_method_call(expr.id) { // The callee is something implementing Fn, FnMut, or FnOnce. // Find the actual method implementation being called and // build the appropriate UFCS call expression with the @@ -271,10 +270,10 @@ fn make_mirror_unadjusted<'a, 'gcx, 'tcx>(cx: &mut Cx<'a, 'gcx, 'tcx>, // Tuple-like ADTs are represented as ExprCall. We convert them here. expr_ty.ty_adt_def().and_then(|adt_def|{ match cx.tcx.expect_def(fun.id) { - Def::Variant(variant_id) => { + Def::VariantCtor(variant_id, CtorKind::Fn) => { Some((adt_def, adt_def.variant_index_with_id(variant_id))) }, - Def::Struct(..) => { + Def::StructCtor(_, CtorKind::Fn) => { Some((adt_def, 0)) }, _ => None @@ -282,7 +281,8 @@ fn make_mirror_unadjusted<'a, 'gcx, 'tcx>(cx: &mut Cx<'a, 'gcx, 'tcx>, }) } else { None }; if let Some((adt_def, index)) = adt_data { - let substs = cx.tcx.node_id_item_substs(fun.id).substs; + let substs = cx.tcx.tables().node_id_item_substs(fun.id) + .unwrap_or_else(|| cx.tcx.intern_substs(&[])); let field_refs = args.iter().enumerate().map(|(idx, e)| FieldExprRef { name: Field::new(idx), expr: e.to_ref() @@ -296,7 +296,7 @@ fn make_mirror_unadjusted<'a, 'gcx, 'tcx>(cx: &mut Cx<'a, 'gcx, 'tcx>, } } else { ExprKind::Call { - ty: cx.tcx.node_id_to_type(fun.id), + ty: cx.tcx.tables().node_id_to_type(fun.id), fun: fun.to_ref(), args: args.to_ref(), } @@ -328,7 +328,7 @@ fn make_mirror_unadjusted<'a, 'gcx, 'tcx>(cx: &mut Cx<'a, 'gcx, 'tcx>, } hir::ExprAssignOp(op, ref lhs, ref rhs) => { - if cx.tcx.is_method_call(expr.id) { + if cx.tcx.tables().is_method_call(expr.id) { let pass_args = if op.node.is_by_value() { PassArgs::ByValue } else { @@ -350,7 +350,7 @@ fn make_mirror_unadjusted<'a, 'gcx, 'tcx>(cx: &mut Cx<'a, 'gcx, 'tcx>, }, hir::ExprBinary(op, ref lhs, ref rhs) => { - if cx.tcx.is_method_call(expr.id) { + if cx.tcx.tables().is_method_call(expr.id) { let pass_args = if op.node.is_by_value() { PassArgs::ByValue } else { @@ -406,7 +406,7 @@ fn make_mirror_unadjusted<'a, 'gcx, 'tcx>(cx: &mut Cx<'a, 'gcx, 'tcx>, } hir::ExprIndex(ref lhs, ref index) => { - if cx.tcx.is_method_call(expr.id) { + if cx.tcx.tables().is_method_call(expr.id) { overloaded_lvalue(cx, expr, ty::MethodCall::expr(expr.id), PassArgs::ByValue, lhs.to_ref(), vec![index]) } else { @@ -418,7 +418,7 @@ fn make_mirror_unadjusted<'a, 'gcx, 'tcx>(cx: &mut Cx<'a, 'gcx, 'tcx>, } hir::ExprUnary(hir::UnOp::UnDeref, ref arg) => { - if cx.tcx.is_method_call(expr.id) { + if cx.tcx.tables().is_method_call(expr.id) { overloaded_lvalue(cx, expr, ty::MethodCall::expr(expr.id), PassArgs::ByValue, arg.to_ref(), vec![]) } else { @@ -427,7 +427,7 @@ fn make_mirror_unadjusted<'a, 'gcx, 'tcx>(cx: &mut Cx<'a, 'gcx, 'tcx>, } hir::ExprUnary(hir::UnOp::UnNot, ref arg) => { - if cx.tcx.is_method_call(expr.id) { + if cx.tcx.tables().is_method_call(expr.id) { overloaded_operator(cx, expr, ty::MethodCall::expr(expr.id), PassArgs::ByValue, arg.to_ref(), vec![]) } else { @@ -439,7 +439,7 @@ fn make_mirror_unadjusted<'a, 'gcx, 'tcx>(cx: &mut Cx<'a, 'gcx, 'tcx>, } hir::ExprUnary(hir::UnOp::UnNeg, ref arg) => { - if cx.tcx.is_method_call(expr.id) { + if cx.tcx.tables().is_method_call(expr.id) { overloaded_operator(cx, expr, ty::MethodCall::expr(expr.id), PassArgs::ByValue, arg.to_ref(), vec![]) } else { @@ -470,10 +470,8 @@ fn make_mirror_unadjusted<'a, 'gcx, 'tcx>(cx: &mut Cx<'a, 'gcx, 'tcx>, base: base.as_ref().map(|base| { FruInfo { base: base.to_ref(), - field_types: cx.tcx.tables - .borrow() - .fru_field_types[&expr.id] - .clone() + field_types: + cx.tcx.tables().fru_field_types[&expr.id].clone() } }) } @@ -512,7 +510,7 @@ fn make_mirror_unadjusted<'a, 'gcx, 'tcx>(cx: &mut Cx<'a, 'gcx, 'tcx>, } hir::ExprClosure(..) => { - let closure_ty = cx.tcx.expr_ty(expr); + let closure_ty = cx.tcx.tables().expr_ty(expr); let (def_id, substs) = match closure_ty.sty { ty::TyClosure(def_id, substs) => (def_id, substs), _ => { @@ -551,7 +549,7 @@ fn make_mirror_unadjusted<'a, 'gcx, 'tcx>(cx: &mut Cx<'a, 'gcx, 'tcx>, hir::ExprRepeat(ref v, ref c) => ExprKind::Repeat { value: v.to_ref(), count: TypedConstVal { - ty: cx.tcx.expr_ty(c), + ty: cx.tcx.tables().expr_ty(c), span: c.span, value: match const_eval::eval_const_expr(cx.tcx.global_tcx(), c) { ConstVal::Integral(ConstInt::Usize(u)) => u, @@ -579,7 +577,7 @@ fn make_mirror_unadjusted<'a, 'gcx, 'tcx>(cx: &mut Cx<'a, 'gcx, 'tcx>, ExprKind::Loop { condition: None, body: block::to_expr_ref(cx, body) }, hir::ExprField(ref source, name) => { - let index = match cx.tcx.expr_ty_adjusted(source).sty { + let index = match cx.tcx.tables().expr_ty_adjusted(source).sty { ty::TyAdt(adt_def, _) => adt_def.variants[0].index_of_field_named(name.node), ref ty => @@ -613,7 +611,7 @@ fn make_mirror_unadjusted<'a, 'gcx, 'tcx>(cx: &mut Cx<'a, 'gcx, 'tcx>, value: value.to_ref(), value_extents: cx.tcx.region_maps.node_extent(value.id) }, - hir::ExprVec(ref fields) => + hir::ExprArray(ref fields) => ExprKind::Vec { fields: fields.to_ref() }, hir::ExprTup(ref fields) => ExprKind::Tuple { fields: fields.to_ref() }, @@ -631,8 +629,7 @@ fn method_callee<'a, 'gcx, 'tcx>(cx: &mut Cx<'a, 'gcx, 'tcx>, expr: &hir::Expr, method_call: ty::MethodCall) -> Expr<'tcx> { - let tables = cx.tcx.tables.borrow(); - let callee = &tables.method_map[&method_call]; + let callee = cx.tcx.tables().method_map[&method_call]; let temp_lifetime = cx.tcx.region_maps.temporary_scope(expr.id); Expr { temp_lifetime: temp_lifetime, @@ -657,7 +654,7 @@ fn to_borrow_kind(m: hir::Mutability) -> BorrowKind { fn convert_arm<'a, 'gcx, 'tcx>(cx: &mut Cx<'a, 'gcx, 'tcx>, arm: &'tcx hir::Arm) -> Arm<'tcx> { Arm { - patterns: arm.pats.iter().map(|p| cx.refutable_pat(p)).collect(), + patterns: arm.pats.iter().map(|p| Pattern::from_hir(cx.tcx, p)).collect(), guard: arm.guard.to_ref(), body: arm.body.to_ref(), } @@ -666,46 +663,31 @@ fn convert_arm<'a, 'gcx, 'tcx>(cx: &mut Cx<'a, 'gcx, 'tcx>, fn convert_path_expr<'a, 'gcx, 'tcx>(cx: &mut Cx<'a, 'gcx, 'tcx>, expr: &'tcx hir::Expr) -> ExprKind<'tcx> { - let substs = cx.tcx.node_id_item_substs(expr.id).substs; - // Otherwise there may be def_map borrow conflicts + let substs = cx.tcx.tables().node_id_item_substs(expr.id) + .unwrap_or_else(|| cx.tcx.intern_substs(&[])); let def = cx.tcx.expect_def(expr.id); let def_id = match def { - // A regular function. - Def::Fn(def_id) | Def::Method(def_id) => def_id, - Def::Struct(def_id) => match cx.tcx.node_id_to_type(expr.id).sty { - // A tuple-struct constructor. Should only be reached if not called in the same - // expression. - ty::TyFnDef(..) => def_id, - // A unit struct which is used as a value. We return a completely different ExprKind - // here to account for this special case. - ty::TyAdt(adt_def, substs) => return ExprKind::Adt { - adt_def: adt_def, - variant_index: 0, - substs: substs, - fields: vec![], - base: None - }, - ref sty => bug!("unexpected sty: {:?}", sty) - }, - Def::Variant(variant_id) => match cx.tcx.node_id_to_type(expr.id).sty { - // A variant constructor. Should only be reached if not called in the same - // expression. - ty::TyFnDef(..) => variant_id, - // A unit variant, similar special case to the struct case above. - ty::TyAdt(adt_def, substs) => { - let index = adt_def.variant_index_with_id(variant_id); - return ExprKind::Adt { + // A regular function, constructor function or a constant. + Def::Fn(def_id) | Def::Method(def_id) | + Def::StructCtor(def_id, CtorKind::Fn) | + Def::VariantCtor(def_id, CtorKind::Fn) | + Def::Const(def_id) | Def::AssociatedConst(def_id) => def_id, + + Def::StructCtor(def_id, CtorKind::Const) | + Def::VariantCtor(def_id, CtorKind::Const) => { + match cx.tcx.tables().node_id_to_type(expr.id).sty { + // A unit struct/variant which is used as a value. + // We return a completely different ExprKind here to account for this special case. + ty::TyAdt(adt_def, substs) => return ExprKind::Adt { adt_def: adt_def, + variant_index: adt_def.variant_index_with_id(def_id), substs: substs, - variant_index: index, fields: vec![], - base: None - }; - }, - ref sty => bug!("unexpected sty: {:?}", sty) - }, - Def::Const(def_id) | - Def::AssociatedConst(def_id) => def_id, + base: None, + }, + ref sty => bug!("unexpected sty: {:?}", sty) + } + } Def::Static(node_id, _) => return ExprKind::StaticRef { id: node_id, @@ -737,7 +719,7 @@ fn convert_var<'a, 'gcx, 'tcx>(cx: &mut Cx<'a, 'gcx, 'tcx>, Def::Upvar(def_id, index, closure_expr_id) => { let id_var = cx.tcx.map.as_local_node_id(def_id).unwrap(); debug!("convert_var(upvar({:?}, {:?}, {:?}))", id_var, index, closure_expr_id); - let var_ty = cx.tcx.node_id_to_type(id_var); + let var_ty = cx.tcx.tables().node_id_to_type(id_var); let body_id = match cx.tcx.map.find(closure_expr_id) { Some(map::NodeExpr(expr)) => { @@ -754,7 +736,7 @@ fn convert_var<'a, 'gcx, 'tcx>(cx: &mut Cx<'a, 'gcx, 'tcx>, }; // FIXME free regions in closures are not right - let closure_ty = cx.tcx.node_id_to_type(closure_expr_id); + let closure_ty = cx.tcx.tables().node_id_to_type(closure_expr_id); // FIXME we're just hard-coding the idea that the // signature will be &self or &mut self and hence will @@ -826,7 +808,7 @@ fn convert_var<'a, 'gcx, 'tcx>(cx: &mut Cx<'a, 'gcx, 'tcx>, var_id: id_var, closure_expr_id: closure_expr_id, }; - let upvar_capture = match cx.tcx.upvar_capture(upvar_id) { + let upvar_capture = match cx.tcx.tables().upvar_capture(upvar_id) { Some(c) => c, None => { span_bug!( @@ -910,7 +892,7 @@ fn overloaded_operator<'a, 'gcx, 'tcx>(cx: &mut Cx<'a, 'gcx, 'tcx>, argrefs.extend( args.iter() .map(|arg| { - let arg_ty = cx.tcx.expr_ty_adjusted(arg); + let arg_ty = cx.tcx.tables().expr_ty_adjusted(arg); let adjusted_ty = cx.tcx.mk_ref(region, ty::TypeAndMut { ty: arg_ty, @@ -948,9 +930,7 @@ fn overloaded_lvalue<'a, 'gcx, 'tcx>(cx: &mut Cx<'a, 'gcx, 'tcx>, // line up (this is because `*x` and `x[y]` represent lvalues): // to find the type &T of the content returned by the method; - let tables = cx.tcx.tables.borrow(); - let callee = &tables.method_map[&method_call]; - let ref_ty = callee.ty.fn_ret(); + let ref_ty = cx.tcx.tables().method_map[&method_call].ty.fn_ret(); let ref_ty = cx.tcx.no_late_bound_regions(&ref_ty).unwrap(); // callees always have all late-bound regions fully instantiated, @@ -979,9 +959,9 @@ fn capture_freevar<'a, 'gcx, 'tcx>(cx: &mut Cx<'a, 'gcx, 'tcx>, var_id: id_var, closure_expr_id: closure_expr.id, }; - let upvar_capture = cx.tcx.upvar_capture(upvar_id).unwrap(); + let upvar_capture = cx.tcx.tables().upvar_capture(upvar_id).unwrap(); let temp_lifetime = cx.tcx.region_maps.temporary_scope(closure_expr.id); - let var_ty = cx.tcx.node_id_to_type(id_var); + let var_ty = cx.tcx.tables().node_id_to_type(id_var); let captured_var = Expr { temp_lifetime: temp_lifetime, ty: var_ty, diff --git a/src/librustc_mir/hair/cx/mod.rs b/src/librustc_mir/hair/cx/mod.rs index 8dd33ad2f9..678db1e544 100644 --- a/src/librustc_mir/hair/cx/mod.rs +++ b/src/librustc_mir/hair/cx/mod.rs @@ -16,7 +16,7 @@ */ use hair::*; -use rustc::mir::repr::*; +use rustc::mir::*; use rustc::mir::transform::MirSource; use rustc::middle::const_val::ConstVal; @@ -27,7 +27,7 @@ use rustc::hir::def_id::DefId; use rustc::hir::intravisit::FnKind; use rustc::hir::map::blocks::FnLikeNode; use rustc::infer::InferCtxt; -use rustc::ty::subst::{Subst, Substs}; +use rustc::ty::subst::Subst; use rustc::ty::{self, Ty, TyCtxt}; use syntax::parse::token; use rustc::hir; @@ -146,7 +146,7 @@ impl<'a, 'gcx, 'tcx> Cx<'a, 'gcx, 'tcx> { params: &[Ty<'tcx>]) -> (Ty<'tcx>, Literal<'tcx>) { let method_name = token::intern(method_name); - let substs = Substs::new_trait(self.tcx, self_ty, params); + let substs = self.tcx.mk_substs_trait(self_ty, params); for trait_item in self.tcx.trait_items(trait_def_id).iter() { match *trait_item { ty::ImplOrTraitItem::MethodTraitItem(ref method) => { @@ -196,5 +196,4 @@ impl<'a, 'gcx, 'tcx> Cx<'a, 'gcx, 'tcx> { mod block; mod expr; -mod pattern; mod to_ref; diff --git a/src/librustc_mir/hair/cx/pattern.rs b/src/librustc_mir/hair/cx/pattern.rs deleted file mode 100644 index 7b8446b184..0000000000 --- a/src/librustc_mir/hair/cx/pattern.rs +++ /dev/null @@ -1,328 +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. - -use hair::*; -use hair::cx::Cx; -use rustc_data_structures::indexed_vec::Idx; -use rustc_const_eval as const_eval; -use rustc::hir::def::Def; -use rustc::hir::pat_util::EnumerateAndAdjustIterator; -use rustc::ty::{self, Ty}; -use rustc::mir::repr::*; -use rustc::hir::{self, PatKind}; -use syntax::ptr::P; -use syntax_pos::Span; - -/// When there are multiple patterns in a single arm, each one has its -/// own node-ids for the bindings. References to the variables always -/// use the node-ids from the first pattern in the arm, so we just -/// remap the ids for all subsequent bindings to the first one. -/// -/// Example: -/// ``` -/// match foo { -/// Test1(flavor /* def 1 */) | -/// Test2(flavor /* def 2 */) if flavor /* ref 1 */.is_tasty() => { ... } -/// _ => { ... } -/// } -/// ``` -struct PatCx<'patcx, 'cx: 'patcx, 'gcx: 'cx+'tcx, 'tcx: 'cx> { - cx: &'patcx mut Cx<'cx, 'gcx, 'tcx>, -} - -impl<'cx, 'gcx, 'tcx> Cx<'cx, 'gcx, 'tcx> { - pub fn irrefutable_pat(&mut self, pat: &hir::Pat) -> Pattern<'tcx> { - PatCx::new(self).to_pattern(pat) - } - - pub fn refutable_pat(&mut self, - pat: &hir::Pat) - -> Pattern<'tcx> { - PatCx::new(self).to_pattern(pat) - } -} - -impl<'patcx, 'cx, 'gcx, 'tcx> PatCx<'patcx, 'cx, 'gcx, 'tcx> { - fn new(cx: &'patcx mut Cx<'cx, 'gcx, 'tcx>) - -> PatCx<'patcx, 'cx, 'gcx, 'tcx> { - PatCx { - cx: cx, - } - } - - fn to_pattern(&mut self, pat: &hir::Pat) -> Pattern<'tcx> { - let mut ty = self.cx.tcx.node_id_to_type(pat.id); - - let kind = match pat.node { - PatKind::Wild => PatternKind::Wild, - - PatKind::Lit(ref value) => { - let value = const_eval::eval_const_expr(self.cx.tcx.global_tcx(), value); - PatternKind::Constant { value: value } - } - - PatKind::Range(ref lo, ref hi) => { - let lo = const_eval::eval_const_expr(self.cx.tcx.global_tcx(), lo); - let lo = Literal::Value { value: lo }; - let hi = const_eval::eval_const_expr(self.cx.tcx.global_tcx(), hi); - let hi = Literal::Value { value: hi }; - PatternKind::Range { lo: lo, hi: hi } - }, - - PatKind::Path(..) => { - match self.cx.tcx.expect_def(pat.id) { - Def::Const(def_id) | Def::AssociatedConst(def_id) => { - let tcx = self.cx.tcx.global_tcx(); - let substs = Some(self.cx.tcx.node_id_item_substs(pat.id).substs); - match const_eval::lookup_const_by_id(tcx, def_id, substs) { - Some((const_expr, _const_ty)) => { - match const_eval::const_expr_to_pat(tcx, - const_expr, - pat.id, - pat.span) { - Ok(pat) => - return self.to_pattern(&pat), - Err(_) => - span_bug!( - pat.span, "illegal constant"), - } - } - None => { - span_bug!( - pat.span, - "cannot eval constant: {:?}", - def_id) - } - } - } - _ => { - self.variant_or_leaf(pat, vec![]) - } - } - } - - PatKind::Ref(ref subpattern, _) | - PatKind::Box(ref subpattern) => { - PatternKind::Deref { subpattern: self.to_pattern(subpattern) } - } - - PatKind::Vec(ref prefix, ref slice, ref suffix) => { - let ty = self.cx.tcx.node_id_to_type(pat.id); - match ty.sty { - ty::TyRef(_, mt) => - PatternKind::Deref { - subpattern: Pattern { - ty: mt.ty, - span: pat.span, - kind: Box::new(self.slice_or_array_pattern(pat.span, mt.ty, prefix, - slice, suffix)), - }, - }, - - ty::TySlice(..) | - ty::TyArray(..) => - self.slice_or_array_pattern(pat.span, ty, prefix, slice, suffix), - - ref sty => - span_bug!( - pat.span, - "unexpanded type for vector pattern: {:?}", - sty), - } - } - - PatKind::Tuple(ref subpatterns, ddpos) => { - match self.cx.tcx.node_id_to_type(pat.id).sty { - ty::TyTuple(ref tys) => { - let subpatterns = - subpatterns.iter() - .enumerate_and_adjust(tys.len(), ddpos) - .map(|(i, subpattern)| FieldPattern { - field: Field::new(i), - pattern: self.to_pattern(subpattern), - }) - .collect(); - - PatternKind::Leaf { subpatterns: subpatterns } - } - - ref sty => span_bug!(pat.span, "unexpected type for tuple pattern: {:?}", sty), - } - } - - PatKind::Binding(bm, ref ident, ref sub) => { - let def_id = self.cx.tcx.expect_def(pat.id).def_id(); - let id = self.cx.tcx.map.as_local_node_id(def_id).unwrap(); - let var_ty = self.cx.tcx.node_id_to_type(pat.id); - let region = match var_ty.sty { - ty::TyRef(r, _) => Some(r), - _ => None, - }; - let (mutability, mode) = match bm { - hir::BindByValue(hir::MutMutable) => - (Mutability::Mut, BindingMode::ByValue), - hir::BindByValue(hir::MutImmutable) => - (Mutability::Not, BindingMode::ByValue), - hir::BindByRef(hir::MutMutable) => - (Mutability::Not, BindingMode::ByRef(region.unwrap(), BorrowKind::Mut)), - hir::BindByRef(hir::MutImmutable) => - (Mutability::Not, BindingMode::ByRef(region.unwrap(), BorrowKind::Shared)), - }; - - // A ref x pattern is the same node used for x, and as such it has - // x's type, which is &T, where we want T (the type being matched). - if let hir::BindByRef(_) = bm { - if let ty::TyRef(_, mt) = ty.sty { - ty = mt.ty; - } else { - bug!("`ref {}` has wrong type {}", ident.node, ty); - } - } - - PatternKind::Binding { - mutability: mutability, - mode: mode, - name: ident.node, - var: id, - ty: var_ty, - subpattern: self.to_opt_pattern(sub), - } - } - - PatKind::TupleStruct(_, ref subpatterns, ddpos) => { - let pat_ty = self.cx.tcx.node_id_to_type(pat.id); - let adt_def = match pat_ty.sty { - ty::TyAdt(adt_def, _) => adt_def, - _ => span_bug!(pat.span, "tuple struct pattern not applied to an ADT"), - }; - let variant_def = adt_def.variant_of_def(self.cx.tcx.expect_def(pat.id)); - - let subpatterns = - subpatterns.iter() - .enumerate_and_adjust(variant_def.fields.len(), ddpos) - .map(|(i, field)| FieldPattern { - field: Field::new(i), - pattern: self.to_pattern(field), - }) - .collect(); - self.variant_or_leaf(pat, subpatterns) - } - - PatKind::Struct(_, ref fields, _) => { - let pat_ty = self.cx.tcx.node_id_to_type(pat.id); - let adt_def = match pat_ty.sty { - ty::TyAdt(adt_def, _) => adt_def, - _ => { - span_bug!( - pat.span, - "struct pattern not applied to an ADT"); - } - }; - let variant_def = adt_def.variant_of_def(self.cx.tcx.expect_def(pat.id)); - - let subpatterns = - fields.iter() - .map(|field| { - let index = variant_def.index_of_field_named(field.node.name); - let index = index.unwrap_or_else(|| { - span_bug!( - pat.span, - "no field with name {:?}", - field.node.name); - }); - FieldPattern { - field: Field::new(index), - pattern: self.to_pattern(&field.node.pat), - } - }) - .collect(); - - self.variant_or_leaf(pat, subpatterns) - } - }; - - Pattern { - span: pat.span, - ty: ty, - kind: Box::new(kind), - } - } - - fn to_patterns(&mut self, pats: &[P]) -> Vec> { - pats.iter().map(|p| self.to_pattern(p)).collect() - } - - fn to_opt_pattern(&mut self, pat: &Option>) -> Option> { - pat.as_ref().map(|p| self.to_pattern(p)) - } - - fn slice_or_array_pattern(&mut self, - span: Span, - ty: Ty<'tcx>, - prefix: &[P], - slice: &Option>, - suffix: &[P]) - -> PatternKind<'tcx> { - match ty.sty { - ty::TySlice(..) => { - // matching a slice or fixed-length array - PatternKind::Slice { - prefix: self.to_patterns(prefix), - slice: self.to_opt_pattern(slice), - suffix: self.to_patterns(suffix), - } - } - - ty::TyArray(_, len) => { - // fixed-length array - assert!(len >= prefix.len() + suffix.len()); - PatternKind::Array { - prefix: self.to_patterns(prefix), - slice: self.to_opt_pattern(slice), - suffix: self.to_patterns(suffix), - } - } - - _ => { - span_bug!(span, "unexpanded macro or bad constant etc"); - } - } - } - - fn variant_or_leaf(&mut self, - pat: &hir::Pat, - subpatterns: Vec>) - -> PatternKind<'tcx> { - match self.cx.tcx.expect_def(pat.id) { - Def::Variant(variant_id) => { - let enum_id = self.cx.tcx.parent_def_id(variant_id).unwrap(); - let adt_def = self.cx.tcx.lookup_adt_def(enum_id); - if adt_def.variants.len() > 1 { - PatternKind::Variant { - adt_def: adt_def, - variant_index: adt_def.variant_index_with_id(variant_id), - subpatterns: subpatterns, - } - } else { - PatternKind::Leaf { subpatterns: subpatterns } - } - } - - Def::Struct(..) | Def::Union(..) | - Def::TyAlias(..) | Def::AssociatedTy(..) => { - PatternKind::Leaf { subpatterns: subpatterns } - } - - def => { - span_bug!(pat.span, "inappropriate def for pattern: {:?}", def); - } - } - } -} diff --git a/src/librustc_mir/hair/mod.rs b/src/librustc_mir/hair/mod.rs index 59137e2bcd..e211334e54 100644 --- a/src/librustc_mir/hair/mod.rs +++ b/src/librustc_mir/hair/mod.rs @@ -14,9 +14,7 @@ //! unit-tested and separated from the Rust source and compiler data //! structures. -use rustc::mir::repr::{BinOp, BorrowKind, Field, Literal, Mutability, UnOp, - TypedConstVal}; -use rustc::middle::const_val::ConstVal; +use rustc::mir::{BinOp, BorrowKind, Field, Literal, UnOp, TypedConstVal}; use rustc::hir::def_id::DefId; use rustc::middle::region::CodeExtent; use rustc::ty::subst::Substs; @@ -28,6 +26,8 @@ use self::cx::Cx; pub mod cx; +pub use rustc_const_eval::pattern::{BindingMode, Pattern, PatternKind, FieldPattern}; + #[derive(Clone, Debug)] pub struct Block<'tcx> { pub extent: CodeExtent, @@ -266,86 +266,12 @@ pub struct Arm<'tcx> { pub body: ExprRef<'tcx>, } -#[derive(Clone, Debug)] -pub struct Pattern<'tcx> { - pub ty: Ty<'tcx>, - pub span: Span, - pub kind: Box>, -} - #[derive(Copy, Clone, Debug)] pub enum LogicalOp { And, Or, } -#[derive(Clone, Debug)] -pub enum PatternKind<'tcx> { - Wild, - - /// x, ref x, x @ P, etc - Binding { - mutability: Mutability, - name: ast::Name, - mode: BindingMode<'tcx>, - var: ast::NodeId, - ty: Ty<'tcx>, - subpattern: Option>, - }, - - /// Foo(...) or Foo{...} or Foo, where `Foo` is a variant name from an adt with >1 variants - Variant { - adt_def: AdtDef<'tcx>, - variant_index: usize, - subpatterns: Vec>, - }, - - /// (...), Foo(...), Foo{...}, or Foo, where `Foo` is a variant name from an adt with 1 variant - Leaf { - subpatterns: Vec>, - }, - - /// box P, &P, &mut P, etc - Deref { - subpattern: Pattern<'tcx>, - }, - - Constant { - value: ConstVal, - }, - - Range { - lo: Literal<'tcx>, - hi: Literal<'tcx>, - }, - - /// matches against a slice, checking the length and extracting elements - Slice { - prefix: Vec>, - slice: Option>, - suffix: Vec>, - }, - - /// fixed match against an array, irrefutable - Array { - prefix: Vec>, - slice: Option>, - suffix: Vec>, - }, -} - -#[derive(Copy, Clone, Debug)] -pub enum BindingMode<'tcx> { - ByValue, - ByRef(&'tcx Region, BorrowKind), -} - -#[derive(Clone, Debug)] -pub struct FieldPattern<'tcx> { - pub field: Field, - pub pattern: Pattern<'tcx>, -} - /////////////////////////////////////////////////////////////////////////// // The Mirror trait diff --git a/src/librustc_mir/lib.rs b/src/librustc_mir/lib.rs index 02f15602d7..aa56daf888 100644 --- a/src/librustc_mir/lib.rs +++ b/src/librustc_mir/lib.rs @@ -22,7 +22,7 @@ Rust MIR: a lowered representation of Rust. Also: an experiment! #![feature(associated_consts)] #![feature(box_patterns)] -#![feature(dotdot_in_tuple_patterns)] +#![cfg_attr(stage0, feature(dotdot_in_tuple_patterns))] #![feature(rustc_diagnostic_macros)] #![feature(rustc_private)] #![feature(staged_api)] diff --git a/src/librustc_mir/mir_map.rs b/src/librustc_mir/mir_map.rs index 5e92a057da..0ffc59fe6b 100644 --- a/src/librustc_mir/mir_map.rs +++ b/src/librustc_mir/mir_map.rs @@ -19,13 +19,12 @@ use build; use rustc::dep_graph::DepNode; use rustc::hir::def_id::DefId; -use rustc::mir::repr::Mir; +use rustc::mir::Mir; use rustc::mir::transform::MirSource; use rustc::mir::visit::MutVisitor; use pretty; use hair::cx::Cx; -use rustc::mir::mir_map::MirMap; use rustc::infer::InferCtxtBuilder; use rustc::traits::Reveal; use rustc::ty::{self, Ty, TyCtxt}; @@ -37,16 +36,10 @@ use syntax_pos::Span; use std::mem; -pub fn build_mir_for_crate<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>) -> MirMap<'tcx> { - let mut map = MirMap::new(tcx.dep_graph.clone()); - { - let mut dump = BuildMir { - tcx: tcx, - map: &mut map, - }; - tcx.visit_all_items_in_krate(DepNode::Mir, &mut dump); - } - map +pub fn build_mir_for_crate<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>) { + tcx.visit_all_items_in_krate(DepNode::Mir, &mut BuildMir { + tcx: tcx + }); } /// A pass to lift all the types and substitutions in a Mir @@ -83,8 +76,7 @@ impl<'a, 'gcx: 'tcx, 'tcx> MutVisitor<'tcx> for GlobalizeMir<'a, 'gcx> { // BuildMir -- walks a crate, looking for fn items and methods to build MIR from struct BuildMir<'a, 'tcx: 'a> { - tcx: TyCtxt<'a, 'tcx, 'tcx>, - map: &'a mut MirMap<'tcx>, + tcx: TyCtxt<'a, 'tcx, 'tcx> } /// Helper type of a temporary returned by BuildMir::cx(...). @@ -93,8 +85,7 @@ struct BuildMir<'a, 'tcx: 'a> { struct CxBuilder<'a, 'gcx: 'a+'tcx, 'tcx: 'a> { src: MirSource, def_id: DefId, - infcx: InferCtxtBuilder<'a, 'gcx, 'tcx>, - map: &'a mut MirMap<'gcx>, + infcx: InferCtxtBuilder<'a, 'gcx, 'tcx> } impl<'a, 'gcx, 'tcx> BuildMir<'a, 'gcx> { @@ -104,8 +95,7 @@ impl<'a, 'gcx, 'tcx> BuildMir<'a, 'gcx> { CxBuilder { src: src, infcx: self.tcx.infer_ctxt(None, Some(param_env), Reveal::NotSpecializable), - def_id: def_id, - map: self.map + def_id: def_id } } } @@ -114,13 +104,14 @@ impl<'a, 'gcx, 'tcx> CxBuilder<'a, 'gcx, 'tcx> { fn build(&'tcx mut self, f: F) where F: for<'b> FnOnce(Cx<'b, 'gcx, 'tcx>) -> (Mir<'tcx>, build::ScopeAuxiliaryVec) { - let src = self.src; - let mir = self.infcx.enter(|infcx| { + let (src, def_id) = (self.src, self.def_id); + self.infcx.enter(|infcx| { let (mut mir, scope_auxiliary) = f(Cx::new(&infcx, src)); // Convert the Mir to global types. + let tcx = infcx.tcx.global_tcx(); let mut globalizer = GlobalizeMir { - tcx: infcx.tcx.global_tcx(), + tcx: tcx, span: mir.span }; globalizer.visit_mir(&mut mir); @@ -128,13 +119,11 @@ impl<'a, 'gcx, 'tcx> CxBuilder<'a, 'gcx, 'tcx> { mem::transmute::>(mir) }; - pretty::dump_mir(infcx.tcx.global_tcx(), "mir_map", &0, - src, &mir, Some(&scope_auxiliary)); + pretty::dump_mir(tcx, "mir_map", &0, src, &mir, Some(&scope_auxiliary)); - mir + let mir = tcx.alloc_mir(mir); + assert!(tcx.mir_map.borrow_mut().insert(def_id, mir).is_none()); }); - - assert!(self.map.map.insert(self.def_id, mir).is_none()) } } @@ -202,7 +191,7 @@ impl<'a, 'tcx> Visitor<'tcx> for BuildMir<'a, 'tcx> { // Array lengths, i.e. [T; constant]. fn visit_ty(&mut self, ty: &'tcx hir::Ty) { - if let hir::TyFixedLengthVec(_, ref length) = ty.node { + if let hir::TyArray(_, ref length) = ty.node { self.build_const_integer(length); } intravisit::walk_ty(self, ty); @@ -225,7 +214,7 @@ impl<'a, 'tcx> Visitor<'tcx> for BuildMir<'a, 'tcx> { id: ast::NodeId) { // fetch the fully liberated fn signature (that is, all bound // types/lifetimes replaced) - let fn_sig = match self.tcx.tables.borrow().liberated_fn_sigs.get(&id) { + let fn_sig = match self.tcx.tables().liberated_fn_sigs.get(&id) { Some(f) => f.clone(), None => { span_bug!(span, "no liberated fn sig for {:?}", id); @@ -259,7 +248,7 @@ fn closure_self_ty<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, closure_expr_id: ast::NodeId, body_id: ast::NodeId) -> Ty<'tcx> { - let closure_ty = tcx.node_id_to_type(closure_expr_id); + let closure_ty = tcx.tables().node_id_to_type(closure_expr_id); // We're just hard-coding the idea that the signature will be // &self or &mut self and hence will have a bound region with diff --git a/src/librustc_mir/pretty.rs b/src/librustc_mir/pretty.rs index 01e2c6308b..d2fc8aeaa2 100644 --- a/src/librustc_mir/pretty.rs +++ b/src/librustc_mir/pretty.rs @@ -11,8 +11,7 @@ use build::{ScopeAuxiliaryVec, ScopeId}; use rustc::hir; use rustc::hir::def_id::DefId; -use rustc::mir::repr::*; -use rustc::mir::mir_map::MirMap; +use rustc::mir::*; use rustc::mir::transform::MirSource; use rustc::ty::TyCtxt; use rustc_data_structures::fnv::FnvHashMap; @@ -90,14 +89,13 @@ pub fn dump_mir<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, /// Write out a human-readable textual representation for the given MIR. pub fn write_mir_pretty<'a, 'b, 'tcx, I>(tcx: TyCtxt<'b, 'tcx, 'tcx>, iter: I, - mir_map: &MirMap<'tcx>, w: &mut Write) -> io::Result<()> where I: Iterator, 'tcx: 'a { let mut first = true; for def_id in iter { - let mir = &mir_map.map[&def_id]; + let mir = &tcx.item_mir(def_id); if first { first = false; @@ -214,6 +212,9 @@ fn comment(tcx: TyCtxt, SourceInfo { span, scope }: SourceInfo) -> String { format!("scope {} at {}", scope.index(), tcx.sess.codemap().span_to_string(span)) } +/// Prints user-defined variables in a scope tree. +/// +/// Returns the total number of variables printed. fn write_scope_tree(tcx: TyCtxt, mir: &Mir, scope_tree: &FnvHashMap>, @@ -234,11 +235,14 @@ fn write_scope_tree(tcx: TyCtxt, writeln!(w, "{0:1$}scope {2} {{", "", indent, child.index())?; // User variable types (including the user's name in a comment). - for (id, var) in mir.var_decls.iter_enumerated() { - // Skip if not declared in this scope. - if var.source_info.scope != child { + for local in mir.vars_iter() { + let var = &mir.local_decls[local]; + let (name, source_info) = if var.source_info.unwrap().scope == child { + (var.name.unwrap(), var.source_info.unwrap()) + } else { + // Not a variable or not declared in this scope. continue; - } + }; let mut_str = if var.mutability == Mutability::Mut { "mut " @@ -251,13 +255,13 @@ fn write_scope_tree(tcx: TyCtxt, INDENT, indent, mut_str, - id, + local, var.ty); writeln!(w, "{0:1$} // \"{2}\" in {3}", indented_var, ALIGN, - var.name, - comment(tcx, var.source_info))?; + name, + comment(tcx, source_info))?; } write_scope_tree(tcx, mir, scope_tree, w, child, depth + 1)?; @@ -291,9 +295,23 @@ fn write_mir_intro<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, } } + // Print return pointer + let indented_retptr = format!("{}let mut {:?}: {};", + INDENT, + RETURN_POINTER, + mir.return_ty); + writeln!(w, "{0:1$} // return pointer", + indented_retptr, + ALIGN)?; + write_scope_tree(tcx, mir, &scope_tree, w, ARGUMENT_VISIBILITY_SCOPE, 1)?; - write_mir_decls(mir, w) + write_temp_decls(mir, w)?; + + // Add an empty line before the first block is printed. + writeln!(w, "")?; + + Ok(()) } fn write_mir_sig(tcx: TyCtxt, src: MirSource, mir: &Mir, w: &mut Write) @@ -313,29 +331,24 @@ fn write_mir_sig(tcx: TyCtxt, src: MirSource, mir: &Mir, w: &mut Write) write!(w, "(")?; // fn argument types. - for (i, arg) in mir.arg_decls.iter_enumerated() { - if i.index() != 0 { + for (i, arg) in mir.args_iter().enumerate() { + if i != 0 { write!(w, ", ")?; } - write!(w, "{:?}: {}", Lvalue::Arg(i), arg.ty)?; + write!(w, "{:?}: {}", Lvalue::Local(arg), mir.local_decls[arg].ty)?; } write!(w, ") -> {}", mir.return_ty) } else { - assert!(mir.arg_decls.is_empty()); + assert_eq!(mir.arg_count, 0); write!(w, ": {} =", mir.return_ty) } } -fn write_mir_decls(mir: &Mir, w: &mut Write) -> io::Result<()> { +fn write_temp_decls(mir: &Mir, w: &mut Write) -> io::Result<()> { // Compiler-introduced temporary types. - for (id, temp) in mir.temp_decls.iter_enumerated() { - writeln!(w, "{}let mut {:?}: {};", INDENT, id, temp.ty)?; - } - - // Wrote any declaration? Add an empty line before the first block is printed. - if !mir.var_decls.is_empty() || !mir.temp_decls.is_empty() { - writeln!(w, "")?; + for temp in mir.temps_iter() { + writeln!(w, "{}let mut {:?}: {};", INDENT, temp, mir.local_decls[temp].ty)?; } Ok(()) diff --git a/src/librustc_mir/transform/add_call_guards.rs b/src/librustc_mir/transform/add_call_guards.rs index c028504d6f..89e644e4fb 100644 --- a/src/librustc_mir/transform/add_call_guards.rs +++ b/src/librustc_mir/transform/add_call_guards.rs @@ -9,7 +9,7 @@ // except according to those terms. use rustc::ty::TyCtxt; -use rustc::mir::repr::*; +use rustc::mir::*; use rustc::mir::transform::{MirPass, MirSource, Pass}; use rustc_data_structures::indexed_vec::{Idx, IndexVec}; diff --git a/src/librustc_mir/transform/copy_prop.rs b/src/librustc_mir/transform/copy_prop.rs index 79fd16012d..8c8c42a1c7 100644 --- a/src/librustc_mir/transform/copy_prop.rs +++ b/src/librustc_mir/transform/copy_prop.rs @@ -29,12 +29,11 @@ //! (non-mutating) use of `SRC`. These restrictions are conservative and may be relaxed in the //! future. -use def_use::{DefUseAnalysis, MirSummary}; -use rustc::mir::repr::{Constant, Local, Location, Lvalue, Mir, Operand, Rvalue, StatementKind}; +use def_use::DefUseAnalysis; +use rustc::mir::{Constant, Local, Location, Lvalue, Mir, Operand, Rvalue, StatementKind}; use rustc::mir::transform::{MirPass, MirSource, Pass}; use rustc::mir::visit::MutVisitor; use rustc::ty::TyCtxt; -use rustc_data_structures::indexed_vec::Idx; use transform::qualify_consts; pub struct CopyPropagation; @@ -78,9 +77,8 @@ impl<'tcx> MirPass<'tcx> for CopyPropagation { def_use_analysis.analyze(mir); let mut changed = false; - for dest_local_index in 0..mir.count_locals() { - let dest_local = Local::new(dest_local_index); - debug!("Considering destination local: {}", mir.format_local(dest_local)); + for dest_local in mir.local_decls.indices() { + debug!("Considering destination local: {:?}", dest_local); let action; let location; @@ -89,19 +87,19 @@ impl<'tcx> MirPass<'tcx> for CopyPropagation { let dest_use_info = def_use_analysis.local_info(dest_local); let dest_def_count = dest_use_info.def_count_not_including_drop(); if dest_def_count == 0 { - debug!(" Can't copy-propagate local: dest {} undefined", - mir.format_local(dest_local)); + debug!(" Can't copy-propagate local: dest {:?} undefined", + dest_local); continue } if dest_def_count > 1 { - debug!(" Can't copy-propagate local: dest {} defined {} times", - mir.format_local(dest_local), + debug!(" Can't copy-propagate local: dest {:?} defined {} times", + dest_local, dest_use_info.def_count()); continue } if dest_use_info.use_count() == 0 { - debug!(" Can't copy-propagate local: dest {} unused", - mir.format_local(dest_local)); + debug!(" Can't copy-propagate local: dest {:?} unused", + dest_local); continue } let dest_lvalue_def = dest_use_info.defs_and_uses.iter().filter(|lvalue_def| { @@ -121,11 +119,11 @@ impl<'tcx> MirPass<'tcx> for CopyPropagation { // That use of the source must be an assignment. match statement.kind { - StatementKind::Assign(ref dest_lvalue, Rvalue::Use(ref operand)) if - Some(dest_local) == mir.local_index(dest_lvalue) => { + StatementKind::Assign(Lvalue::Local(local), Rvalue::Use(ref operand)) if + local == dest_local => { let maybe_action = match *operand { Operand::Consume(ref src_lvalue) => { - Action::local_copy(mir, &def_use_analysis, src_lvalue) + Action::local_copy(&def_use_analysis, src_lvalue) } Operand::Constant(ref src_constant) => { Action::constant(src_constant) @@ -162,15 +160,14 @@ enum Action<'tcx> { } impl<'tcx> Action<'tcx> { - fn local_copy(mir: &Mir<'tcx>, def_use_analysis: &DefUseAnalysis, src_lvalue: &Lvalue<'tcx>) + fn local_copy(def_use_analysis: &DefUseAnalysis, src_lvalue: &Lvalue<'tcx>) -> Option> { // The source must be a local. - let src_local = match mir.local_index(src_lvalue) { - Some(src_local) => src_local, - None => { - debug!(" Can't copy-propagate local: source is not a local"); - return None - } + let src_local = if let Lvalue::Local(local) = *src_lvalue { + local + } else { + debug!(" Can't copy-propagate local: source is not a local"); + return None; }; // We're trying to copy propagate a local. @@ -225,9 +222,9 @@ impl<'tcx> Action<'tcx> { // First, remove all markers. // // FIXME(pcwalton): Don't do this. Merge live ranges instead. - debug!(" Replacing all uses of {} with {} (local)", - mir.format_local(dest_local), - mir.format_local(src_local)); + debug!(" Replacing all uses of {:?} with {:?} (local)", + dest_local, + src_local); for lvalue_use in &def_use_analysis.local_info(dest_local).defs_and_uses { if lvalue_use.context.is_storage_marker() { mir.make_statement_nop(lvalue_use.location) @@ -240,7 +237,7 @@ impl<'tcx> Action<'tcx> { } // Replace all uses of the destination local with the source local. - let src_lvalue = Lvalue::from_local(mir, src_local); + let src_lvalue = Lvalue::Local(src_local); def_use_analysis.replace_all_defs_and_uses_with(dest_local, mir, src_lvalue); // Finally, zap the now-useless assignment instruction. @@ -253,8 +250,8 @@ impl<'tcx> Action<'tcx> { // First, remove all markers. // // FIXME(pcwalton): Don't do this. Merge live ranges instead. - debug!(" Replacing all uses of {} with {:?} (constant)", - mir.format_local(dest_local), + debug!(" Replacing all uses of {:?} with {:?} (constant)", + dest_local, src_constant); let dest_local_info = def_use_analysis.local_info(dest_local); for lvalue_use in &dest_local_info.defs_and_uses { @@ -264,8 +261,7 @@ impl<'tcx> Action<'tcx> { } // Replace all uses of the destination local with the constant. - let mut visitor = ConstantPropagationVisitor::new(MirSummary::new(mir), - dest_local, + let mut visitor = ConstantPropagationVisitor::new(dest_local, src_constant); for dest_lvalue_use in &dest_local_info.defs_and_uses { visitor.visit_location(mir, dest_lvalue_use.location) @@ -298,17 +294,15 @@ impl<'tcx> Action<'tcx> { struct ConstantPropagationVisitor<'tcx> { dest_local: Local, constant: Constant<'tcx>, - mir_summary: MirSummary, uses_replaced: usize, } impl<'tcx> ConstantPropagationVisitor<'tcx> { - fn new(mir_summary: MirSummary, dest_local: Local, constant: Constant<'tcx>) + fn new(dest_local: Local, constant: Constant<'tcx>) -> ConstantPropagationVisitor<'tcx> { ConstantPropagationVisitor { dest_local: dest_local, constant: constant, - mir_summary: mir_summary, uses_replaced: 0, } } @@ -319,16 +313,11 @@ impl<'tcx> MutVisitor<'tcx> for ConstantPropagationVisitor<'tcx> { self.super_operand(operand, location); match *operand { - Operand::Consume(ref lvalue) => { - if self.mir_summary.local_index(lvalue) != Some(self.dest_local) { - return - } - } - Operand::Constant(_) => return, + Operand::Consume(Lvalue::Local(local)) if local == self.dest_local => {} + _ => return, } *operand = Operand::Constant(self.constant.clone()); self.uses_replaced += 1 } } - diff --git a/src/librustc_mir/transform/deaggregator.rs b/src/librustc_mir/transform/deaggregator.rs index 77af02c18c..fcdeae6d6c 100644 --- a/src/librustc_mir/transform/deaggregator.rs +++ b/src/librustc_mir/transform/deaggregator.rs @@ -9,10 +9,9 @@ // except according to those terms. use rustc::ty::TyCtxt; -use rustc::mir::repr::*; +use rustc::mir::*; use rustc::mir::transform::{MirPass, MirSource, Pass}; use rustc_data_structures::indexed_vec::Idx; -use rustc::ty::VariantKind; pub struct Deaggregator; @@ -129,10 +128,7 @@ fn get_aggregate_statement_index<'a, 'tcx, 'b>(start: usize, } debug!("getting variant {:?}", variant); debug!("for adt_def {:?}", adt_def); - let variant_def = &adt_def.variants[variant]; - if variant_def.kind == VariantKind::Struct { - return Some(i); - } + return Some(i); }; None } diff --git a/src/librustc_mir/transform/dump_mir.rs b/src/librustc_mir/transform/dump_mir.rs index 694b017bbd..b8fd9fb12a 100644 --- a/src/librustc_mir/transform/dump_mir.rs +++ b/src/librustc_mir/transform/dump_mir.rs @@ -13,7 +13,7 @@ use std::fmt; use rustc::ty::TyCtxt; -use rustc::mir::repr::*; +use rustc::mir::*; use rustc::mir::transform::{Pass, MirPass, MirPassHook, MirSource}; use pretty; diff --git a/src/librustc_mir/transform/erase_regions.rs b/src/librustc_mir/transform/erase_regions.rs index 485ca3ea84..cebd9dd966 100644 --- a/src/librustc_mir/transform/erase_regions.rs +++ b/src/librustc_mir/transform/erase_regions.rs @@ -14,7 +14,7 @@ use rustc::ty::subst::Substs; use rustc::ty::{Ty, TyCtxt}; -use rustc::mir::repr::*; +use rustc::mir::*; use rustc::mir::visit::MutVisitor; use rustc::mir::transform::{MirPass, MirSource, Pass}; diff --git a/src/librustc_mir/transform/instcombine.rs b/src/librustc_mir/transform/instcombine.rs index a0331f03b0..a01724d6d0 100644 --- a/src/librustc_mir/transform/instcombine.rs +++ b/src/librustc_mir/transform/instcombine.rs @@ -10,11 +10,12 @@ //! Performs various peephole optimizations. -use rustc::mir::repr::{Location, Lvalue, Mir, Operand, ProjectionElem, Rvalue}; +use rustc::mir::{Location, Lvalue, Mir, Operand, ProjectionElem, Rvalue, Local}; use rustc::mir::transform::{MirPass, MirSource, Pass}; use rustc::mir::visit::{MutVisitor, Visitor}; use rustc::ty::TyCtxt; use rustc::util::nodemap::FnvHashSet; +use rustc_data_structures::indexed_vec::Idx; use std::mem; pub struct InstCombine { @@ -61,7 +62,8 @@ impl<'tcx> MutVisitor<'tcx> for InstCombine { debug!("Replacing `&*`: {:?}", rvalue); let new_lvalue = match *rvalue { Rvalue::Ref(_, _, Lvalue::Projection(ref mut projection)) => { - mem::replace(&mut projection.base, Lvalue::ReturnPointer) + // Replace with dummy + mem::replace(&mut projection.base, Lvalue::Local(Local::new(0))) } _ => bug!("Detected `&*` but didn't find `&*`!"), }; @@ -107,4 +109,3 @@ impl<'b, 'a, 'tcx> Visitor<'tcx> for OptimizationFinder<'b, 'a, 'tcx> { struct OptimizationList { and_stars: FnvHashSet, } - diff --git a/src/librustc_mir/transform/mod.rs b/src/librustc_mir/transform/mod.rs index 7bcb89b589..ae255f70fb 100644 --- a/src/librustc_mir/transform/mod.rs +++ b/src/librustc_mir/transform/mod.rs @@ -9,7 +9,7 @@ // except according to those terms. pub mod simplify_branches; -pub mod simplify_cfg; +pub mod simplify; pub mod erase_regions; pub mod no_landing_pads; pub mod type_check; diff --git a/src/librustc_mir/transform/no_landing_pads.rs b/src/librustc_mir/transform/no_landing_pads.rs index 32fddd293c..6ef5720b33 100644 --- a/src/librustc_mir/transform/no_landing_pads.rs +++ b/src/librustc_mir/transform/no_landing_pads.rs @@ -12,7 +12,7 @@ //! specified. use rustc::ty::TyCtxt; -use rustc::mir::repr::*; +use rustc::mir::*; use rustc::mir::visit::MutVisitor; use rustc::mir::transform::{Pass, MirPass, MirSource}; diff --git a/src/librustc_mir/transform/promote_consts.rs b/src/librustc_mir/transform/promote_consts.rs index 57de68fce1..41698574e0 100644 --- a/src/librustc_mir/transform/promote_consts.rs +++ b/src/librustc_mir/transform/promote_consts.rs @@ -22,7 +22,7 @@ //! initialization and can otherwise silence errors, if //! move analysis runs after promotion on broken MIR. -use rustc::mir::repr::*; +use rustc::mir::*; use rustc::mir::visit::{LvalueContext, MutVisitor, Visitor}; use rustc::mir::traversal::ReversePostorder; use rustc::ty::TyCtxt; @@ -30,6 +30,7 @@ use syntax_pos::Span; use rustc_data_structures::indexed_vec::{IndexVec, Idx}; +use std::iter; use std::mem; use std::usize; @@ -74,15 +75,24 @@ pub enum Candidate { ShuffleIndices(BasicBlock) } -struct TempCollector { - temps: IndexVec, - span: Span +struct TempCollector<'tcx> { + temps: IndexVec, + span: Span, + mir: &'tcx Mir<'tcx>, } -impl<'tcx> Visitor<'tcx> for TempCollector { - fn visit_lvalue(&mut self, lvalue: &Lvalue<'tcx>, context: LvalueContext, location: Location) { +impl<'tcx> Visitor<'tcx> for TempCollector<'tcx> { + fn visit_lvalue(&mut self, + lvalue: &Lvalue<'tcx>, + context: LvalueContext<'tcx>, + location: Location) { self.super_lvalue(lvalue, context, location); - if let Lvalue::Temp(index) = *lvalue { + if let Lvalue::Local(index) = *lvalue { + // We're only interested in temporaries + if self.mir.local_kind(index) != LocalKind::Temp { + return; + } + // Ignore drops, if the temp gets promoted, // then it's constant and thus drop is noop. // Storage live ranges are also irrelevant. @@ -126,10 +136,11 @@ impl<'tcx> Visitor<'tcx> for TempCollector { } } -pub fn collect_temps(mir: &Mir, rpo: &mut ReversePostorder) -> IndexVec { +pub fn collect_temps(mir: &Mir, rpo: &mut ReversePostorder) -> IndexVec { let mut collector = TempCollector { - temps: IndexVec::from_elem(TempState::Undefined, &mir.temp_decls), - span: mir.span + temps: IndexVec::from_elem(TempState::Undefined, &mir.local_decls), + span: mir.span, + mir: mir, }; for (bb, data) in rpo { collector.visit_basic_block_data(bb, data); @@ -140,7 +151,7 @@ pub fn collect_temps(mir: &Mir, rpo: &mut ReversePostorder) -> IndexVec { source: &'a mut Mir<'tcx>, promoted: Mir<'tcx>, - temps: &'a mut IndexVec, + temps: &'a mut IndexVec, /// If true, all nested temps are also kept in the /// source MIR, not moved to the promoted MIR. @@ -163,7 +174,7 @@ impl<'a, 'tcx> Promoter<'a, 'tcx> { }) } - fn assign(&mut self, dest: Lvalue<'tcx>, rvalue: Rvalue<'tcx>, span: Span) { + fn assign(&mut self, dest: Local, rvalue: Rvalue<'tcx>, span: Span) { let last = self.promoted.basic_blocks().last().unwrap(); let data = &mut self.promoted[last]; data.statements.push(Statement { @@ -171,13 +182,13 @@ impl<'a, 'tcx> Promoter<'a, 'tcx> { span: span, scope: ARGUMENT_VISIBILITY_SCOPE }, - kind: StatementKind::Assign(dest, rvalue) + kind: StatementKind::Assign(Lvalue::Local(dest), rvalue) }); } /// Copy the initialization of this temp to the /// promoted MIR, recursing through temps. - fn promote_temp(&mut self, temp: Temp) -> Temp { + fn promote_temp(&mut self, temp: Local) -> Local { let old_keep_original = self.keep_original; let (bb, stmt_idx) = match self.temps[temp] { TempState::Defined { @@ -259,20 +270,19 @@ impl<'a, 'tcx> Promoter<'a, 'tcx> { }); } - let new_temp = self.promoted.temp_decls.push(TempDecl { - ty: self.source.temp_decls[temp].ty - }); + let new_temp = self.promoted.local_decls.push( + LocalDecl::new_temp(self.source.local_decls[temp].ty)); // Inject the Rvalue or Call into the promoted MIR. if stmt_idx < no_stmts { - self.assign(Lvalue::Temp(new_temp), rvalue.unwrap(), source_info.span); + self.assign(new_temp, rvalue.unwrap(), source_info.span); } else { let last = self.promoted.basic_blocks().last().unwrap(); let new_target = self.new_block(); let mut call = call.unwrap(); match call { TerminatorKind::Call { ref mut destination, ..} => { - *destination = Some((Lvalue::Temp(new_temp), new_target)); + *destination = Some((Lvalue::Local(new_temp), new_target)); } _ => bug!() } @@ -315,11 +325,12 @@ impl<'a, 'tcx> Promoter<'a, 'tcx> { } } }; - self.visit_rvalue(&mut rvalue, Location{ + self.visit_rvalue(&mut rvalue, Location { block: BasicBlock::new(0), statement_index: usize::MAX }); - self.assign(Lvalue::ReturnPointer, rvalue, span); + + self.assign(RETURN_POINTER, rvalue, span); self.source.promoted.push(self.promoted); } } @@ -330,8 +341,10 @@ impl<'a, 'tcx> MutVisitor<'tcx> for Promoter<'a, 'tcx> { lvalue: &mut Lvalue<'tcx>, context: LvalueContext<'tcx>, location: Location) { - if let Lvalue::Temp(ref mut temp) = *lvalue { - *temp = self.promote_temp(*temp); + if let Lvalue::Local(ref mut temp) = *lvalue { + if self.source.local_kind(*temp) == LocalKind::Temp { + *temp = self.promote_temp(*temp); + } } self.super_lvalue(lvalue, context, location); } @@ -339,7 +352,7 @@ impl<'a, 'tcx> MutVisitor<'tcx> for Promoter<'a, 'tcx> { pub fn promote_candidates<'a, 'tcx>(mir: &mut Mir<'tcx>, tcx: TyCtxt<'a, 'tcx, 'tcx>, - mut temps: IndexVec, + mut temps: IndexVec, candidates: Vec) { // Visit candidates in reverse, in case they're nested. for candidate in candidates.into_iter().rev() { @@ -353,7 +366,7 @@ pub fn promote_candidates<'a, 'tcx>(mir: &mut Mir<'tcx>, "expected assignment to promote"); } }; - if let Lvalue::Temp(index) = *dest { + if let Lvalue::Local(index) = *dest { if temps[index] == TempState::PromotedOut { // Already promoted. continue; @@ -376,8 +389,10 @@ pub fn promote_candidates<'a, 'tcx>(mir: &mut Mir<'tcx>, } }; + // Declare return pointer local + let initial_locals = iter::once(LocalDecl::new_return_pointer(ty)).collect(); + let mut promoter = Promoter { - source: mir, promoted: Mir::new( IndexVec::new(), Some(VisibilityScopeData { @@ -386,12 +401,12 @@ pub fn promote_candidates<'a, 'tcx>(mir: &mut Mir<'tcx>, }).into_iter().collect(), IndexVec::new(), ty, - IndexVec::new(), - IndexVec::new(), - IndexVec::new(), + initial_locals, + 0, vec![], span ), + source: mir, temps: &mut temps, keep_original: false }; @@ -400,13 +415,13 @@ pub fn promote_candidates<'a, 'tcx>(mir: &mut Mir<'tcx>, } // Eliminate assignments to, and drops of promoted temps. - let promoted = |index: Temp| temps[index] == TempState::PromotedOut; + let promoted = |index: Local| temps[index] == TempState::PromotedOut; for block in mir.basic_blocks_mut() { block.statements.retain(|statement| { match statement.kind { - StatementKind::Assign(Lvalue::Temp(index), _) | - StatementKind::StorageLive(Lvalue::Temp(index)) | - StatementKind::StorageDead(Lvalue::Temp(index)) => { + StatementKind::Assign(Lvalue::Local(index), _) | + StatementKind::StorageLive(Lvalue::Local(index)) | + StatementKind::StorageDead(Lvalue::Local(index)) => { !promoted(index) } _ => true @@ -414,7 +429,7 @@ pub fn promote_candidates<'a, 'tcx>(mir: &mut Mir<'tcx>, }); let terminator = block.terminator_mut(); match terminator.kind { - TerminatorKind::Drop { location: Lvalue::Temp(index), target, .. } => { + TerminatorKind::Drop { location: Lvalue::Local(index), target, .. } => { if promoted(index) { terminator.kind = TerminatorKind::Goto { target: target diff --git a/src/librustc_mir/transform/qualify_consts.rs b/src/librustc_mir/transform/qualify_consts.rs index 2c03af2c8e..b33a7060e3 100644 --- a/src/librustc_mir/transform/qualify_consts.rs +++ b/src/librustc_mir/transform/qualify_consts.rs @@ -16,7 +16,6 @@ use rustc_data_structures::bitvec::BitVector; use rustc_data_structures::indexed_vec::{IndexVec, Idx}; -use rustc::dep_graph::DepNode; use rustc::hir; use rustc::hir::map as hir_map; use rustc::hir::def_id::DefId; @@ -25,10 +24,9 @@ use rustc::hir::map::blocks::FnLikeNode; use rustc::traits::{self, Reveal}; use rustc::ty::{self, TyCtxt, Ty}; use rustc::ty::cast::CastTy; -use rustc::mir::repr::*; -use rustc::mir::mir_map::MirMap; -use rustc::mir::traversal::{self, ReversePostorder}; -use rustc::mir::transform::{Pass, MirMapPass, MirPassHook, MirSource}; +use rustc::mir::*; +use rustc::mir::traversal::ReversePostorder; +use rustc::mir::transform::{Pass, MirPass, MirSource}; use rustc::mir::visit::{LvalueContext, Visitor}; use rustc::util::nodemap::DefIdMap; use syntax::abi::Abi; @@ -142,12 +140,11 @@ struct Qualifier<'a, 'gcx: 'a+'tcx, 'tcx: 'a> { tcx: TyCtxt<'a, 'gcx, 'tcx>, param_env: ty::ParameterEnvironment<'tcx>, qualif_map: &'a mut DefIdMap, - mir_map: Option<&'a MirMap<'tcx>>, - temp_qualif: IndexVec>, + temp_qualif: IndexVec>, return_qualif: Option, qualif: Qualif, const_fn_arg_vars: BitVector, - temp_promotion_state: IndexVec, + temp_promotion_state: IndexVec, promotion_candidates: Vec } @@ -155,7 +152,6 @@ impl<'a, 'tcx> Qualifier<'a, 'tcx, 'tcx> { fn new(tcx: TyCtxt<'a, 'tcx, 'tcx>, param_env: ty::ParameterEnvironment<'tcx>, qualif_map: &'a mut DefIdMap, - mir_map: Option<&'a MirMap<'tcx>>, def_id: DefId, mir: &'a Mir<'tcx>, mode: Mode) @@ -172,11 +168,10 @@ impl<'a, 'tcx> Qualifier<'a, 'tcx, 'tcx> { tcx: tcx, param_env: param_env, qualif_map: qualif_map, - mir_map: mir_map, - temp_qualif: IndexVec::from_elem(None, &mir.temp_decls), + temp_qualif: IndexVec::from_elem(None, &mir.local_decls), return_qualif: None, qualif: Qualif::empty(), - const_fn_arg_vars: BitVector::new(mir.var_decls.len()), + const_fn_arg_vars: BitVector::new(mir.local_decls.len()), temp_promotion_state: temps, promotion_candidates: vec![] } @@ -332,8 +327,10 @@ impl<'a, 'tcx> Qualifier<'a, 'tcx, 'tcx> { // Only handle promotable temps in non-const functions. if self.mode == Mode::Fn { - if let Lvalue::Temp(index) = *dest { - if self.temp_promotion_state[index].is_promotable() { + if let Lvalue::Local(index) = *dest { + if self.mir.local_kind(index) == LocalKind::Temp + && self.temp_promotion_state[index].is_promotable() { + debug!("store to promotable temp {:?}", index); store(&mut self.temp_qualif[index]); } } @@ -341,13 +338,20 @@ impl<'a, 'tcx> Qualifier<'a, 'tcx, 'tcx> { } match *dest { - Lvalue::Temp(index) => store(&mut self.temp_qualif[index]), - Lvalue::ReturnPointer => store(&mut self.return_qualif), + Lvalue::Local(index) if self.mir.local_kind(index) == LocalKind::Temp => { + debug!("store to temp {:?}", index); + store(&mut self.temp_qualif[index]) + } + Lvalue::Local(index) if self.mir.local_kind(index) == LocalKind::ReturnPointer => { + debug!("store to return pointer {:?}", index); + store(&mut self.return_qualif) + } Lvalue::Projection(box Projection { - base: Lvalue::Temp(index), + base: Lvalue::Local(index), elem: ProjectionElem::Deref - }) if self.mir.temp_decls[index].ty.is_unique() + }) if self.mir.local_kind(index) == LocalKind::Temp + && self.mir.local_decls[index].ty.is_unique() && self.temp_qualif[index].map_or(false, |qualif| { qualif.intersects(Qualif::NOT_CONST) }) => { @@ -366,6 +370,8 @@ impl<'a, 'tcx> Qualifier<'a, 'tcx, 'tcx> { /// Qualify a whole const, static initializer or const fn. fn qualify_const(&mut self) -> Qualif { + debug!("qualifying {} {}", self.mode, self.tcx.item_path_str(self.def_id)); + let mir = self.mir; let mut seen_blocks = BitVector::new(mir.basic_blocks().len()); @@ -399,7 +405,7 @@ impl<'a, 'tcx> Qualifier<'a, 'tcx, 'tcx> { TerminatorKind::Return => { // Check for unused values. This usually means // there are extra statements in the AST. - for temp in mir.temp_decls.indices() { + for temp in mir.temps_iter() { if self.temp_qualif[temp].is_none() { continue; } @@ -424,9 +430,10 @@ impl<'a, 'tcx> Qualifier<'a, 'tcx, 'tcx> { // Make sure there are no extra unassigned variables. self.qualif = Qualif::NOT_CONST; - for index in 0..mir.var_decls.len() { - if !self.const_fn_arg_vars.contains(index) { - self.assign(&Lvalue::Var(Var::new(index)), Location { + for index in mir.vars_iter() { + if !self.const_fn_arg_vars.contains(index.index()) { + debug!("unassigned variable {:?}", index); + self.assign(&Lvalue::Local(index), Location { block: bb, statement_index: usize::MAX, }); @@ -480,23 +487,28 @@ impl<'a, 'tcx> Visitor<'tcx> for Qualifier<'a, 'tcx, 'tcx> { context: LvalueContext<'tcx>, location: Location) { match *lvalue { - Lvalue::Arg(_) => { - self.add(Qualif::FN_ARGUMENT); - } - Lvalue::Var(_) => { - self.add(Qualif::NOT_CONST); - } - Lvalue::Temp(index) => { - if !self.temp_promotion_state[index].is_promotable() { - self.add(Qualif::NOT_PROMOTABLE); + Lvalue::Local(local) => match self.mir.local_kind(local) { + LocalKind::ReturnPointer => { + self.not_const(); } + LocalKind::Arg => { + self.add(Qualif::FN_ARGUMENT); + } + LocalKind::Var => { + self.add(Qualif::NOT_CONST); + } + LocalKind::Temp => { + if !self.temp_promotion_state[local].is_promotable() { + self.add(Qualif::NOT_PROMOTABLE); + } - if let Some(qualif) = self.temp_qualif[index] { - self.add(qualif); - } else { - self.not_const(); + if let Some(qualif) = self.temp_qualif[local] { + self.add(qualif); + } else { + self.not_const(); + } } - } + }, Lvalue::Static(_) => { self.add(Qualif::STATIC); if self.mode == Mode::Const || self.mode == Mode::ConstFn { @@ -505,9 +517,6 @@ impl<'a, 'tcx> Visitor<'tcx> for Qualifier<'a, 'tcx, 'tcx> { a constant instead", self.mode); } } - Lvalue::ReturnPointer => { - self.not_const(); - } Lvalue::Projection(ref proj) => { self.nest(|this| { this.super_lvalue(lvalue, context, location); @@ -581,7 +590,6 @@ impl<'a, 'tcx> Visitor<'tcx> for Qualifier<'a, 'tcx, 'tcx> { } else { let qualif = qualify_const_item_cached(self.tcx, self.qualif_map, - self.mir_map, def_id); self.add(qualif); } @@ -685,8 +693,10 @@ impl<'a, 'tcx> Visitor<'tcx> for Qualifier<'a, 'tcx, 'tcx> { if self.mode == Mode::Fn || self.mode == Mode::ConstFn { if !self.qualif.intersects(Qualif::NEVER_PROMOTE) { // We can only promote direct borrows of temps. - if let Lvalue::Temp(_) = *lvalue { - self.promotion_candidates.push(candidate); + if let Lvalue::Local(local) = *lvalue { + if self.mir.local_kind(local) == LocalKind::Temp { + self.promotion_candidates.push(candidate); + } } } } @@ -879,17 +889,21 @@ impl<'a, 'tcx> Visitor<'tcx> for Qualifier<'a, 'tcx, 'tcx> { self.visit_rvalue(rvalue, location); // Check the allowed const fn argument forms. - if let (Mode::ConstFn, &Lvalue::Var(index)) = (self.mode, dest) { - if self.const_fn_arg_vars.insert(index.index()) { + if let (Mode::ConstFn, &Lvalue::Local(index)) = (self.mode, dest) { + if self.mir.local_kind(index) == LocalKind::Var && + self.const_fn_arg_vars.insert(index.index()) { + // Direct use of an argument is permitted. - if let Rvalue::Use(Operand::Consume(Lvalue::Arg(_))) = *rvalue { - return; + if let Rvalue::Use(Operand::Consume(Lvalue::Local(local))) = *rvalue { + if self.mir.local_kind(local) == LocalKind::Arg { + return; + } } // Avoid a generic error for other uses of arguments. if self.qualif.intersects(Qualif::FN_ARGUMENT) { - let decl = &self.mir.var_decls[index]; - span_err!(self.tcx.sess, decl.source_info.span, E0022, + let decl = &self.mir.local_decls[index]; + span_err!(self.tcx.sess, decl.source_info.unwrap().span, E0022, "arguments of constant functions can only \ be immutable by-value bindings"); return; @@ -929,7 +943,6 @@ impl<'a, 'tcx> Visitor<'tcx> for Qualifier<'a, 'tcx, 'tcx> { fn qualify_const_item_cached<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, qualif_map: &mut DefIdMap, - mir_map: Option<&MirMap<'tcx>>, def_id: DefId) -> Qualif { match qualif_map.entry(def_id) { @@ -940,124 +953,100 @@ fn qualify_const_item_cached<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, } } - let extern_mir; - let param_env_and_mir = if def_id.is_local() { - mir_map.and_then(|map| map.map.get(&def_id)).map(|mir| { - let node_id = tcx.map.as_local_node_id(def_id).unwrap(); - (ty::ParameterEnvironment::for_item(tcx, node_id), mir) - }) - } else if let Some(mir) = tcx.sess.cstore.maybe_get_item_mir(tcx, def_id) { - // These should only be monomorphic constants. - extern_mir = mir; - Some((tcx.empty_parameter_environment(), &extern_mir)) + let param_env = if def_id.is_local() { + let node_id = tcx.map.as_local_node_id(def_id).unwrap(); + ty::ParameterEnvironment::for_item(tcx, node_id) } else { - None + // These should only be monomorphic constants. + tcx.empty_parameter_environment() }; - let (param_env, mir) = param_env_and_mir.unwrap_or_else(|| { - bug!("missing constant MIR for {}", tcx.item_path_str(def_id)) - }); - - let mut qualifier = Qualifier::new(tcx, param_env, qualif_map, mir_map, - def_id, mir, Mode::Const); + let mir = &tcx.item_mir(def_id); + let mut qualifier = Qualifier::new(tcx, param_env, qualif_map, def_id, mir, Mode::Const); let qualif = qualifier.qualify_const(); qualifier.qualif_map.insert(def_id, qualif); qualif } -pub struct QualifyAndPromoteConstants; +#[derive(Default)] +pub struct QualifyAndPromoteConstants { + qualif_map: DefIdMap +} impl Pass for QualifyAndPromoteConstants {} -impl<'tcx> MirMapPass<'tcx> for QualifyAndPromoteConstants { - fn run_pass<'a>(&mut self, - tcx: TyCtxt<'a, 'tcx, 'tcx>, - map: &mut MirMap<'tcx>, - hooks: &mut [Box MirPassHook<'s>>]) { - let mut qualif_map = DefIdMap(); - - // First, visit `const` items, potentially recursing, to get - // accurate MUTABLE_INTERIOR and NEEDS_DROP qualifications. - let keys = map.map.keys(); - for &def_id in &keys { - let _task = tcx.dep_graph.in_task(DepNode::Mir(def_id)); - let id = tcx.map.as_local_node_id(def_id).unwrap(); - let src = MirSource::from_node(tcx, id); - if let MirSource::Const(_) = src { - qualify_const_item_cached(tcx, &mut qualif_map, Some(map), def_id); +impl<'tcx> MirPass<'tcx> for QualifyAndPromoteConstants { + fn run_pass<'a>(&mut self, tcx: TyCtxt<'a, 'tcx, 'tcx>, + src: MirSource, mir: &mut Mir<'tcx>) { + let id = src.item_id(); + let def_id = tcx.map.local_def_id(id); + let mode = match src { + MirSource::Fn(_) => { + if is_const_fn(tcx, def_id) { + Mode::ConstFn + } else { + Mode::Fn + } } - } - - // Then, handle everything else, without recursing, - // as the MIR map is not shared, since promotion - // in functions (including `const fn`) mutates it. - for &def_id in &keys { - let _task = tcx.dep_graph.in_task(DepNode::Mir(def_id)); - let id = tcx.map.as_local_node_id(def_id).unwrap(); - let src = MirSource::from_node(tcx, id); - let mode = match src { - MirSource::Fn(_) => { - if is_const_fn(tcx, def_id) { - Mode::ConstFn - } else { - Mode::Fn + MirSource::Const(_) => { + match self.qualif_map.entry(def_id) { + Entry::Occupied(_) => return, + Entry::Vacant(entry) => { + // Guard against `const` recursion. + entry.insert(Qualif::RECURSIVE); } } - MirSource::Const(_) => continue, - MirSource::Static(_, hir::MutImmutable) => Mode::Static, - MirSource::Static(_, hir::MutMutable) => Mode::StaticMut, - MirSource::Promoted(..) => bug!() - }; - let param_env = ty::ParameterEnvironment::for_item(tcx, id); - - let mir = map.map.get_mut(&def_id).unwrap(); - for hook in &mut *hooks { - hook.on_mir_pass(tcx, src, mir, self, false); + Mode::Const } - - if mode == Mode::Fn || mode == Mode::ConstFn { - // This is ugly because Qualifier holds onto mir, - // which can't be mutated until its scope ends. - let (temps, candidates) = { - let mut qualifier = Qualifier::new(tcx, param_env, &mut qualif_map, - None, def_id, mir, mode); - if mode == Mode::ConstFn { - // Enforce a constant-like CFG for `const fn`. - qualifier.qualify_const(); - } else { - while let Some((bb, data)) = qualifier.rpo.next() { - qualifier.visit_basic_block_data(bb, data); - } + MirSource::Static(_, hir::MutImmutable) => Mode::Static, + MirSource::Static(_, hir::MutMutable) => Mode::StaticMut, + MirSource::Promoted(..) => return + }; + let param_env = ty::ParameterEnvironment::for_item(tcx, id); + + if mode == Mode::Fn || mode == Mode::ConstFn { + // This is ugly because Qualifier holds onto mir, + // which can't be mutated until its scope ends. + let (temps, candidates) = { + let mut qualifier = Qualifier::new(tcx, param_env, + &mut self.qualif_map, + def_id, mir, mode); + if mode == Mode::ConstFn { + // Enforce a constant-like CFG for `const fn`. + qualifier.qualify_const(); + } else { + while let Some((bb, data)) = qualifier.rpo.next() { + qualifier.visit_basic_block_data(bb, data); } + } - (qualifier.temp_promotion_state, - qualifier.promotion_candidates) - }; + (qualifier.temp_promotion_state, qualifier.promotion_candidates) + }; - // Do the actual promotion, now that we know what's viable. - promote_consts::promote_candidates(mir, tcx, temps, candidates); - } else { - let mut qualifier = Qualifier::new(tcx, param_env, &mut qualif_map, - None, def_id, mir, mode); - qualifier.qualify_const(); - } + // Do the actual promotion, now that we know what's viable. + promote_consts::promote_candidates(mir, tcx, temps, candidates); + } else { + let mut qualifier = Qualifier::new(tcx, param_env, + &mut self.qualif_map, + def_id, mir, mode); + let qualif = qualifier.qualify_const(); - for hook in &mut *hooks { - hook.on_mir_pass(tcx, src, mir, self, true); + if mode == Mode::Const { + qualifier.qualif_map.insert(def_id, qualif); } + } - // Statics must be Sync. - if mode == Mode::Static { - let ty = mir.return_ty; - tcx.infer_ctxt(None, None, Reveal::NotSpecializable).enter(|infcx| { - let cause = traits::ObligationCause::new(mir.span, id, traits::SharedStatic); - let mut fulfillment_cx = traits::FulfillmentContext::new(); - fulfillment_cx.register_builtin_bound(&infcx, ty, ty::BoundSync, cause); - if let Err(err) = fulfillment_cx.select_all_or_error(&infcx) { - infcx.report_fulfillment_errors(&err); - } - }); - } + // Statics must be Sync. + if mode == Mode::Static { + let ty = mir.return_ty; + tcx.infer_ctxt(None, None, Reveal::NotSpecializable).enter(|infcx| { + let cause = traits::ObligationCause::new(mir.span, id, traits::SharedStatic); + let mut fulfillment_cx = traits::FulfillmentContext::new(); + fulfillment_cx.register_builtin_bound(&infcx, ty, ty::BoundSync, cause); + if let Err(err) = fulfillment_cx.select_all_or_error(&infcx) { + infcx.report_fulfillment_errors(&err); + } + }); } } } diff --git a/src/librustc_mir/transform/simplify_cfg.rs b/src/librustc_mir/transform/simplify.rs similarity index 62% rename from src/librustc_mir/transform/simplify_cfg.rs rename to src/librustc_mir/transform/simplify.rs index 8e1b7b4497..d5fc90289e 100644 --- a/src/librustc_mir/transform/simplify_cfg.rs +++ b/src/librustc_mir/transform/simplify.rs @@ -8,36 +8,41 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -//! A pass that removes various redundancies in the CFG. It should be -//! called after every significant CFG modification to tidy things -//! up. +//! A number of passes which remove various redundancies in the CFG. //! -//! This pass must also be run before any analysis passes because it removes -//! dead blocks, and some of these can be ill-typed. +//! The `SimplifyCfg` pass gets rid of unnecessary blocks in the CFG, whereas the `SimplifyLocals` +//! gets rid of all the unnecessary local variable declarations. //! -//! The cause of that is that typeck lets most blocks whose end is not -//! reachable have an arbitrary return type, rather than having the -//! usual () return type (as a note, typeck's notion of reachability -//! is in fact slightly weaker than MIR CFG reachability - see #31617). +//! The `SimplifyLocals` pass is kinda expensive and therefore not very suitable to be run often. +//! Most of the passes should not care or be impacted in meaningful ways due to extra locals +//! either, so running the pass once, right before translation, should suffice. +//! +//! On the other side of the spectrum, the `SimplifyCfg` pass is considerably cheap to run, thus +//! one should run it after every pass which may modify CFG in significant ways. This pass must +//! also be run before any analysis passes because it removes dead blocks, and some of these can be +//! ill-typed. +//! +//! The cause of this typing issue is typeck allowing most blocks whose end is not reachable have +//! an arbitrary return type, rather than having the usual () return type (as a note, typeck's +//! notion of reachability is in fact slightly weaker than MIR CFG reachability - see #31617). A +//! standard example of the situation is: //! -//! A standard example of the situation is: //! ```rust //! fn example() { //! let _a: char = { return; }; //! } //! ``` //! -//! Here the block (`{ return; }`) has the return type `char`, -//! rather than `()`, but the MIR we naively generate still contains -//! the `_a = ()` write in the unreachable block "after" the return. - +//! Here the block (`{ return; }`) has the return type `char`, rather than `()`, but the MIR we +//! naively generate still contains the `_a = ()` write in the unreachable block "after" the +//! return. use rustc_data_structures::bitvec::BitVector; use rustc_data_structures::indexed_vec::{Idx, IndexVec}; use rustc::ty::TyCtxt; -use rustc::mir::repr::*; +use rustc::mir::*; use rustc::mir::transform::{MirPass, MirSource, Pass}; -use rustc::mir::traversal; +use rustc::mir::visit::{MutVisitor, Visitor, LvalueContext}; use std::fmt; pub struct SimplifyCfg<'a> { label: &'a str } @@ -50,6 +55,7 @@ impl<'a> SimplifyCfg<'a> { impl<'l, 'tcx> MirPass<'tcx> for SimplifyCfg<'l> { fn run_pass<'a>(&mut self, _tcx: TyCtxt<'a, 'tcx, 'tcx>, _src: MirSource, mir: &mut Mir<'tcx>) { + debug!("SimplifyCfg({:?}) - simplifying {:?}", self.label, mir); CfgSimplifier::new(mir).simplify(); remove_dead_blocks(mir); @@ -78,6 +84,8 @@ impl<'a, 'tcx: 'a> CfgSimplifier<'a, 'tcx> { // we can't use mir.predecessors() here because that counts // dead blocks, which we don't want to. + pred_count[START_BLOCK] = 1; + for (_, data) in traversal::preorder(mir) { if let Some(ref term) = data.terminator { for &tgt in term.successors().iter() { @@ -157,8 +165,16 @@ impl<'a, 'tcx: 'a> CfgSimplifier<'a, 'tcx> { debug!("collapsing goto chain from {:?} to {:?}", *start, target); *changed |= *start != target; - self.pred_count[target] += 1; - self.pred_count[*start] -= 1; + + if self.pred_count[*start] == 1 { + // This is the last reference to *start, so the pred-count to + // to target is moved into the current block. + self.pred_count[*start] = 0; + } else { + self.pred_count[target] += 1; + self.pred_count[*start] -= 1; + } + *start = target; } @@ -247,3 +263,87 @@ fn remove_dead_blocks(mir: &mut Mir) { } } } + + +pub struct SimplifyLocals; + +impl Pass for SimplifyLocals { + fn name(&self) -> ::std::borrow::Cow<'static, str> { "SimplifyLocals".into() } +} + +impl<'tcx> MirPass<'tcx> for SimplifyLocals { + fn run_pass<'a>(&mut self, _: TyCtxt<'a, 'tcx, 'tcx>, _: MirSource, mir: &mut Mir<'tcx>) { + let mut marker = DeclMarker { locals: BitVector::new(mir.local_decls.len()) }; + marker.visit_mir(mir); + // Return pointer and arguments are always live + marker.locals.insert(0); + for idx in mir.args_iter() { + marker.locals.insert(idx.index()); + } + let map = make_local_map(&mut mir.local_decls, marker.locals); + // Update references to all vars and tmps now + LocalUpdater { map: map }.visit_mir(mir); + mir.local_decls.shrink_to_fit(); + } +} + +/// Construct the mapping while swapping out unused stuff out from the `vec`. +fn make_local_map<'tcx, I: Idx, V>(vec: &mut IndexVec, mask: BitVector) -> Vec { + let mut map: Vec = ::std::iter::repeat(!0).take(vec.len()).collect(); + let mut used = 0; + for alive_index in mask.iter() { + map[alive_index] = used; + if alive_index != used { + vec.swap(alive_index, used); + } + used += 1; + } + vec.truncate(used); + map +} + +struct DeclMarker { + pub locals: BitVector, +} + +impl<'tcx> Visitor<'tcx> for DeclMarker { + fn visit_lvalue(&mut self, lval: &Lvalue<'tcx>, ctx: LvalueContext<'tcx>, loc: Location) { + if ctx == LvalueContext::StorageLive || ctx == LvalueContext::StorageDead { + // ignore these altogether, they get removed along with their otherwise unused decls. + return; + } + if let Lvalue::Local(ref v) = *lval { + self.locals.insert(v.index()); + } + self.super_lvalue(lval, ctx, loc); + } +} + +struct LocalUpdater { + map: Vec, +} + +impl<'tcx> MutVisitor<'tcx> for LocalUpdater { + fn visit_basic_block_data(&mut self, block: BasicBlock, data: &mut BasicBlockData<'tcx>) { + // Remove unnecessary StorageLive and StorageDead annotations. + data.statements.retain(|stmt| { + match stmt.kind { + StatementKind::StorageLive(ref lval) | StatementKind::StorageDead(ref lval) => { + match *lval { + Lvalue::Local(l) => self.map[l.index()] != !0, + _ => true + } + } + _ => true + } + }); + self.super_basic_block_data(block, data); + } + fn visit_lvalue(&mut self, lval: &mut Lvalue<'tcx>, ctx: LvalueContext<'tcx>, loc: Location) { + match *lval { + Lvalue::Local(ref mut l) => *l = Local::new(self.map[l.index()]), + _ => (), + }; + self.super_lvalue(lval, ctx, loc); + } +} diff --git a/src/librustc_mir/transform/simplify_branches.rs b/src/librustc_mir/transform/simplify_branches.rs index 407e216161..8759a340d7 100644 --- a/src/librustc_mir/transform/simplify_branches.rs +++ b/src/librustc_mir/transform/simplify_branches.rs @@ -13,7 +13,7 @@ use rustc::ty::TyCtxt; use rustc::middle::const_val::ConstVal; use rustc::mir::transform::{MirPass, MirSource, Pass}; -use rustc::mir::repr::*; +use rustc::mir::*; use std::fmt; diff --git a/src/librustc_mir/transform/type_check.rs b/src/librustc_mir/transform/type_check.rs index 7b6a2f5580..9d3afe541c 100644 --- a/src/librustc_mir/transform/type_check.rs +++ b/src/librustc_mir/transform/type_check.rs @@ -15,10 +15,10 @@ use rustc::infer::{self, InferCtxt, InferOk}; use rustc::traits::{self, Reveal}; use rustc::ty::fold::TypeFoldable; use rustc::ty::{self, Ty, TyCtxt, TypeVariants}; -use rustc::mir::repr::*; +use rustc::mir::*; use rustc::mir::tcx::LvalueTy; use rustc::mir::transform::{MirPass, MirSource, Pass}; -use rustc::mir::visit::{self, Visitor}; +use rustc::mir::visit::Visitor; use std::fmt; use syntax::ast; use syntax_pos::{Span, DUMMY_SP}; @@ -90,14 +90,8 @@ impl<'a, 'b, 'gcx, 'tcx> Visitor<'tcx> for TypeVerifier<'a, 'b, 'gcx, 'tcx> { fn visit_mir(&mut self, mir: &Mir<'tcx>) { self.sanitize_type(&"return type", mir.return_ty); - for var_decl in &mir.var_decls { - self.sanitize_type(var_decl, var_decl.ty); - } - for (n, arg_decl) in mir.arg_decls.iter().enumerate() { - self.sanitize_type(&(n, arg_decl), arg_decl.ty); - } - for (n, tmp_decl) in mir.temp_decls.iter().enumerate() { - self.sanitize_type(&(n, tmp_decl), tmp_decl.ty); + for local_decl in &mir.local_decls { + self.sanitize_type(local_decl, local_decl.ty); } if self.errors_reported { return; @@ -131,14 +125,9 @@ impl<'a, 'b, 'gcx, 'tcx> TypeVerifier<'a, 'b, 'gcx, 'tcx> { fn sanitize_lvalue(&mut self, lvalue: &Lvalue<'tcx>, location: Location) -> LvalueTy<'tcx> { debug!("sanitize_lvalue: {:?}", lvalue); match *lvalue { - Lvalue::Var(index) => LvalueTy::Ty { ty: self.mir.var_decls[index].ty }, - Lvalue::Temp(index) => LvalueTy::Ty { ty: self.mir.temp_decls[index].ty }, - Lvalue::Arg(index) => LvalueTy::Ty { ty: self.mir.arg_decls[index].ty }, + Lvalue::Local(index) => LvalueTy::Ty { ty: self.mir.local_decls[index].ty }, Lvalue::Static(def_id) => LvalueTy::Ty { ty: self.tcx().lookup_item_type(def_id).ty }, - Lvalue::ReturnPointer => { - LvalueTy::Ty { ty: self.mir.return_ty } - } Lvalue::Projection(ref proj) => { let base_ty = self.sanitize_lvalue(&proj.base, location); if let LvalueTy::Ty { ty } = base_ty { @@ -380,9 +369,9 @@ impl<'a, 'gcx, 'tcx> TypeChecker<'a, 'gcx, 'tcx> { StatementKind::StorageLive(ref lv) | StatementKind::StorageDead(ref lv) => { match *lv { - Lvalue::Temp(_) | Lvalue::Var(_) => {} + Lvalue::Local(_) => {} _ => { - span_mirbug!(self, stmt, "bad lvalue: expected temp or var"); + span_mirbug!(self, stmt, "bad lvalue: expected local"); } } } @@ -711,6 +700,8 @@ impl TypeckMir { impl<'tcx> MirPass<'tcx> for TypeckMir { fn run_pass<'a>(&mut self, tcx: TyCtxt<'a, 'tcx, 'tcx>, src: MirSource, mir: &mut Mir<'tcx>) { + debug!("run_pass: {}", tcx.node_path_str(src.item_id())); + if tcx.sess.err_count() > 0 { // compiling a broken program can obviously result in a // broken MIR, so try not to report duplicate errors. diff --git a/src/librustc_passes/ast_validation.rs b/src/librustc_passes/ast_validation.rs index 5096a574e2..828efbf373 100644 --- a/src/librustc_passes/ast_validation.rs +++ b/src/librustc_passes/ast_validation.rs @@ -190,8 +190,16 @@ impl<'a> Visitor for AstValidator<'a> { } ItemKind::Trait(.., ref trait_items) => { for trait_item in trait_items { - if let TraitItemKind::Method(ref sig, _) = trait_item.node { + if let TraitItemKind::Method(ref sig, ref block) = trait_item.node { self.check_trait_fn_not_const(sig.constness); + if block.is_none() { + self.check_decl_no_pat(&sig.decl, |span, _| { + self.session.add_lint(lint::builtin::PATTERNS_IN_FNS_WITHOUT_BODY, + trait_item.id, span, + "patterns aren't allowed in methods \ + without bodies".to_string()); + }); + } } } } diff --git a/src/librustc_passes/consts.rs b/src/librustc_passes/consts.rs index f919e42b6b..f23539e88f 100644 --- a/src/librustc_passes/consts.rs +++ b/src/librustc_passes/consts.rs @@ -33,7 +33,7 @@ use rustc_const_eval::ErrKind::{ErroneousReferencedConstant, MiscBinaryOp, NonCo use rustc_const_eval::ErrKind::UnresolvedPath; use rustc_const_eval::EvalHint::ExprTypeChecked; use rustc_const_math::{ConstMathErr, Op}; -use rustc::hir::def::Def; +use rustc::hir::def::{Def, CtorKind}; use rustc::hir::def_id::DefId; use rustc::middle::expr_use_visitor as euv; use rustc::middle::mem_categorization as mc; @@ -319,7 +319,7 @@ impl<'a, 'tcx, 'v> Visitor<'v> for CheckCrateVisitor<'a, 'tcx> { let mut outer = self.qualif; self.qualif = ConstQualif::empty(); - let node_ty = self.tcx.node_id_to_type(ex.id); + let node_ty = self.tcx.tables().node_id_to_type(ex.id); check_expr(self, ex, node_ty); check_adjustments(self, ex); @@ -449,14 +449,14 @@ fn check_expr<'a, 'tcx>(v: &mut CheckCrateVisitor<'a, 'tcx>, e: &hir::Expr, node match e.node { hir::ExprUnary(..) | hir::ExprBinary(..) | - hir::ExprIndex(..) if v.tcx.tables.borrow().method_map.contains_key(&method_call) => { + hir::ExprIndex(..) if v.tcx.tables().method_map.contains_key(&method_call) => { v.add_qualif(ConstQualif::NOT_CONST); } hir::ExprBox(_) => { v.add_qualif(ConstQualif::NOT_CONST); } hir::ExprUnary(op, ref inner) => { - match v.tcx.node_id_to_type(inner.id).sty { + match v.tcx.tables().node_id_to_type(inner.id).sty { ty::TyRawPtr(_) => { assert!(op == hir::UnDeref); @@ -466,7 +466,7 @@ fn check_expr<'a, 'tcx>(v: &mut CheckCrateVisitor<'a, 'tcx>, e: &hir::Expr, node } } hir::ExprBinary(op, ref lhs, _) => { - match v.tcx.node_id_to_type(lhs.id).sty { + match v.tcx.tables().node_id_to_type(lhs.id).sty { ty::TyRawPtr(_) => { assert!(op.node == hir::BiEq || op.node == hir::BiNe || op.node == hir::BiLe || op.node == hir::BiLt || @@ -489,20 +489,12 @@ fn check_expr<'a, 'tcx>(v: &mut CheckCrateVisitor<'a, 'tcx>, e: &hir::Expr, node } hir::ExprPath(..) => { match v.tcx.expect_def(e.id) { - Def::Variant(..) => { - // Count the discriminator or function pointer. - v.add_qualif(ConstQualif::NON_ZERO_SIZED); - } - Def::Struct(..) => { - if let ty::TyFnDef(..) = node_ty.sty { - // Count the function pointer. - v.add_qualif(ConstQualif::NON_ZERO_SIZED); - } - } - Def::Fn(..) | Def::Method(..) => { - // Count the function pointer. + Def::VariantCtor(_, CtorKind::Const) => { + // Size is determined by the whole enum, may be non-zero. v.add_qualif(ConstQualif::NON_ZERO_SIZED); } + Def::VariantCtor(..) | Def::StructCtor(..) | + Def::Fn(..) | Def::Method(..) => {} Def::Static(..) => { match v.mode { Mode::Static | Mode::StaticMut => {} @@ -511,7 +503,8 @@ fn check_expr<'a, 'tcx>(v: &mut CheckCrateVisitor<'a, 'tcx>, e: &hir::Expr, node } } Def::Const(did) | Def::AssociatedConst(did) => { - let substs = Some(v.tcx.node_id_item_substs(e.id).substs); + let substs = Some(v.tcx.tables().node_id_item_substs(e.id) + .unwrap_or_else(|| v.tcx.intern_substs(&[]))); if let Some((expr, _)) = lookup_const_by_id(v.tcx, did, substs) { let inner = v.global_expr(Mode::Const, expr); v.add_qualif(inner); @@ -539,9 +532,9 @@ fn check_expr<'a, 'tcx>(v: &mut CheckCrateVisitor<'a, 'tcx>, e: &hir::Expr, node } // The callee is an arbitrary expression, it doesn't necessarily have a definition. let is_const = match v.tcx.expect_def_or_none(callee.id) { - Some(Def::Struct(..)) => true, - Some(Def::Variant(..)) => { - // Count the discriminator. + Some(Def::StructCtor(_, CtorKind::Fn)) | + Some(Def::VariantCtor(_, CtorKind::Fn)) => { + // `NON_ZERO_SIZED` is about the call result, not about the ctor itself. v.add_qualif(ConstQualif::NON_ZERO_SIZED); true } @@ -563,7 +556,7 @@ fn check_expr<'a, 'tcx>(v: &mut CheckCrateVisitor<'a, 'tcx>, e: &hir::Expr, node } } hir::ExprMethodCall(..) => { - let method = v.tcx.tables.borrow().method_map[&method_call]; + let method = v.tcx.tables().method_map[&method_call]; let is_const = match v.tcx.impl_or_trait_item(method.def_id).container() { ty::ImplContainer(_) => v.handle_const_fn_call(e, method.def_id, node_ty), ty::TraitContainer(_) => false @@ -573,9 +566,11 @@ fn check_expr<'a, 'tcx>(v: &mut CheckCrateVisitor<'a, 'tcx>, e: &hir::Expr, node } } hir::ExprStruct(..) => { - // unsafe_cell_type doesn't necessarily exist with no_core - if Some(v.tcx.expect_def(e.id).def_id()) == v.tcx.lang_items.unsafe_cell_type() { - v.add_qualif(ConstQualif::MUTABLE_MEM); + if let ty::TyAdt(adt, ..) = v.tcx.tables().expr_ty(e).sty { + // unsafe_cell_type doesn't necessarily exist with no_core + if Some(adt.did) == v.tcx.lang_items.unsafe_cell_type() { + v.add_qualif(ConstQualif::MUTABLE_MEM); + } } } @@ -602,7 +597,7 @@ fn check_expr<'a, 'tcx>(v: &mut CheckCrateVisitor<'a, 'tcx>, e: &hir::Expr, node hir::ExprIndex(..) | hir::ExprField(..) | hir::ExprTupField(..) | - hir::ExprVec(_) | + hir::ExprArray(_) | hir::ExprType(..) | hir::ExprTup(..) => {} @@ -630,16 +625,18 @@ fn check_expr<'a, 'tcx>(v: &mut CheckCrateVisitor<'a, 'tcx>, e: &hir::Expr, node /// Check the adjustments of an expression fn check_adjustments<'a, 'tcx>(v: &mut CheckCrateVisitor<'a, 'tcx>, e: &hir::Expr) { - match v.tcx.tables.borrow().adjustments.get(&e.id) { + use rustc::ty::adjustment::*; + + match v.tcx.tables().adjustments.get(&e.id).map(|adj| adj.kind) { None | - Some(&ty::adjustment::AdjustNeverToAny(..)) | - Some(&ty::adjustment::AdjustReifyFnPointer) | - Some(&ty::adjustment::AdjustUnsafeFnPointer) | - Some(&ty::adjustment::AdjustMutToConstPointer) => {} + Some(Adjust::NeverToAny) | + Some(Adjust::ReifyFnPointer) | + Some(Adjust::UnsafeFnPointer) | + Some(Adjust::MutToConstPointer) => {} - Some(&ty::adjustment::AdjustDerefRef(ty::adjustment::AutoDerefRef { autoderefs, .. })) => { + Some(Adjust::DerefRef { autoderefs, .. }) => { if (0..autoderefs as u32) - .any(|autoderef| v.tcx.is_overloaded_autoderef(e.id, autoderef)) { + .any(|autoderef| v.tcx.tables().is_overloaded_autoderef(e.id, autoderef)) { v.add_qualif(ConstQualif::NOT_CONST); } } diff --git a/src/librustc_passes/hir_stats.rs b/src/librustc_passes/hir_stats.rs new file mode 100644 index 0000000000..1858671589 --- /dev/null +++ b/src/librustc_passes/hir_stats.rs @@ -0,0 +1,374 @@ +// Copyright 2016 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +// The visitors in this module collect sizes and counts of the most important +// pieces of AST and HIR. The resulting numbers are good approximations but not +// completely accurate (some things might be counted twice, others missed). + +use rustc::hir; +use rustc::hir::intravisit as hir_visit; +use rustc::util::common::to_readable_str; +use rustc::util::nodemap::{FnvHashMap, FnvHashSet}; +use syntax::ast::{self, NodeId, AttrId}; +use syntax::visit as ast_visit; +use syntax_pos::Span; + +#[derive(Copy, Clone, PartialEq, Eq, Hash)] +enum Id { + Node(NodeId), + Attr(AttrId), + None, +} + +struct NodeData { + count: usize, + size: usize, +} + +struct StatCollector<'k> { + krate: Option<&'k hir::Crate>, + data: FnvHashMap<&'static str, NodeData>, + seen: FnvHashSet, +} + +pub fn print_hir_stats(krate: &hir::Crate) { + let mut collector = StatCollector { + krate: Some(krate), + data: FnvHashMap(), + seen: FnvHashSet(), + }; + hir_visit::walk_crate(&mut collector, krate); + collector.print("HIR STATS"); +} + +pub fn print_ast_stats(krate: &ast::Crate, title: &str) { + let mut collector = StatCollector { + krate: None, + data: FnvHashMap(), + seen: FnvHashSet(), + }; + ast_visit::walk_crate(&mut collector, krate); + collector.print(title); +} + +impl<'k> StatCollector<'k> { + + fn record(&mut self, label: &'static str, id: Id, node: &T) { + if id != Id::None { + if !self.seen.insert(id) { + return + } + } + + let entry = self.data.entry(label).or_insert(NodeData { + count: 0, + size: 0, + }); + + entry.count += 1; + entry.size = ::std::mem::size_of_val(node); + } + + fn print(&self, title: &str) { + let mut stats: Vec<_> = self.data.iter().collect(); + + stats.sort_by_key(|&(_, ref d)| d.count * d.size); + + let mut total_size = 0; + + println!("\n{}\n", title); + + println!("{:<18}{:>18}{:>14}{:>14}", + "Name", "Accumulated Size", "Count", "Item Size"); + println!("----------------------------------------------------------------"); + + for (label, data) in stats { + println!("{:<18}{:>18}{:>14}{:>14}", + label, + to_readable_str(data.count * data.size), + to_readable_str(data.count), + to_readable_str(data.size)); + + total_size += data.count * data.size; + } + println!("----------------------------------------------------------------"); + println!("{:<18}{:>18}\n", + "Total", + to_readable_str(total_size)); + } +} + +impl<'v> hir_visit::Visitor<'v> for StatCollector<'v> { + + fn visit_nested_item(&mut self, id: hir::ItemId) { + let nested_item = self.krate.unwrap().item(id.id); + self.visit_item(nested_item) + } + + fn visit_item(&mut self, i: &'v hir::Item) { + self.record("Item", Id::Node(i.id), i); + hir_visit::walk_item(self, i) + } + + /////////////////////////////////////////////////////////////////////////// + + fn visit_mod(&mut self, m: &'v hir::Mod, _s: Span, n: NodeId) { + self.record("Mod", Id::None, m); + hir_visit::walk_mod(self, m, n) + } + fn visit_foreign_item(&mut self, i: &'v hir::ForeignItem) { + self.record("ForeignItem", Id::Node(i.id), i); + hir_visit::walk_foreign_item(self, i) + } + fn visit_local(&mut self, l: &'v hir::Local) { + self.record("Local", Id::Node(l.id), l); + hir_visit::walk_local(self, l) + } + fn visit_block(&mut self, b: &'v hir::Block) { + self.record("Block", Id::Node(b.id), b); + hir_visit::walk_block(self, b) + } + fn visit_stmt(&mut self, s: &'v hir::Stmt) { + self.record("Stmt", Id::Node(s.node.id()), s); + hir_visit::walk_stmt(self, s) + } + fn visit_arm(&mut self, a: &'v hir::Arm) { + self.record("Arm", Id::None, a); + hir_visit::walk_arm(self, a) + } + fn visit_pat(&mut self, p: &'v hir::Pat) { + self.record("Pat", Id::Node(p.id), p); + hir_visit::walk_pat(self, p) + } + fn visit_decl(&mut self, d: &'v hir::Decl) { + self.record("Decl", Id::None, d); + hir_visit::walk_decl(self, d) + } + fn visit_expr(&mut self, ex: &'v hir::Expr) { + self.record("Expr", Id::Node(ex.id), ex); + hir_visit::walk_expr(self, ex) + } + + fn visit_ty(&mut self, t: &'v hir::Ty) { + self.record("Ty", Id::Node(t.id), t); + hir_visit::walk_ty(self, t) + } + + fn visit_fn(&mut self, + fk: hir_visit::FnKind<'v>, + fd: &'v hir::FnDecl, + b: &'v hir::Block, + s: Span, + id: NodeId) { + self.record("FnDecl", Id::None, fd); + hir_visit::walk_fn(self, fk, fd, b, s, id) + } + + fn visit_where_predicate(&mut self, predicate: &'v hir::WherePredicate) { + self.record("WherePredicate", Id::None, predicate); + hir_visit::walk_where_predicate(self, predicate) + } + + fn visit_trait_item(&mut self, ti: &'v hir::TraitItem) { + self.record("TraitItem", Id::Node(ti.id), ti); + hir_visit::walk_trait_item(self, ti) + } + fn visit_impl_item(&mut self, ii: &'v hir::ImplItem) { + self.record("ImplItem", Id::Node(ii.id), ii); + hir_visit::walk_impl_item(self, ii) + } + + fn visit_ty_param_bound(&mut self, bounds: &'v hir::TyParamBound) { + self.record("TyParamBound", Id::None, bounds); + hir_visit::walk_ty_param_bound(self, bounds) + } + + fn visit_struct_field(&mut self, s: &'v hir::StructField) { + self.record("StructField", Id::Node(s.id), s); + hir_visit::walk_struct_field(self, s) + } + + fn visit_variant(&mut self, + v: &'v hir::Variant, + g: &'v hir::Generics, + item_id: NodeId) { + self.record("Variant", Id::None, v); + hir_visit::walk_variant(self, v, g, item_id) + } + fn visit_lifetime(&mut self, lifetime: &'v hir::Lifetime) { + self.record("Lifetime", Id::Node(lifetime.id), lifetime); + hir_visit::walk_lifetime(self, lifetime) + } + fn visit_lifetime_def(&mut self, lifetime: &'v hir::LifetimeDef) { + self.record("LifetimeDef", Id::None, lifetime); + hir_visit::walk_lifetime_def(self, lifetime) + } + fn visit_path(&mut self, path: &'v hir::Path, _id: NodeId) { + self.record("Path", Id::None, path); + hir_visit::walk_path(self, path) + } + fn visit_path_list_item(&mut self, + prefix: &'v hir::Path, + item: &'v hir::PathListItem) { + self.record("PathListItem", Id::Node(item.node.id), item); + hir_visit::walk_path_list_item(self, prefix, item) + } + fn visit_path_segment(&mut self, + path_span: Span, + path_segment: &'v hir::PathSegment) { + self.record("PathSegment", Id::None, path_segment); + hir_visit::walk_path_segment(self, path_span, path_segment) + } + + fn visit_assoc_type_binding(&mut self, type_binding: &'v hir::TypeBinding) { + self.record("TypeBinding", Id::Node(type_binding.id), type_binding); + hir_visit::walk_assoc_type_binding(self, type_binding) + } + fn visit_attribute(&mut self, attr: &'v ast::Attribute) { + self.record("Attribute", Id::Attr(attr.node.id), attr); + } + fn visit_macro_def(&mut self, macro_def: &'v hir::MacroDef) { + self.record("MacroDef", Id::Node(macro_def.id), macro_def); + hir_visit::walk_macro_def(self, macro_def) + } +} + +impl<'v> ast_visit::Visitor for StatCollector<'v> { + + fn visit_mod(&mut self, m: &ast::Mod, _s: Span, _n: NodeId) { + self.record("Mod", Id::None, m); + ast_visit::walk_mod(self, m) + } + + fn visit_foreign_item(&mut self, i: &ast::ForeignItem) { + self.record("ForeignItem", Id::None, i); + ast_visit::walk_foreign_item(self, i) + } + + fn visit_item(&mut self, i: &ast::Item) { + self.record("Item", Id::None, i); + ast_visit::walk_item(self, i) + } + + fn visit_local(&mut self, l: &ast::Local) { + self.record("Local", Id::None, l); + ast_visit::walk_local(self, l) + } + + fn visit_block(&mut self, b: &ast::Block) { + self.record("Block", Id::None, b); + ast_visit::walk_block(self, b) + } + + fn visit_stmt(&mut self, s: &ast::Stmt) { + self.record("Stmt", Id::None, s); + ast_visit::walk_stmt(self, s) + } + + fn visit_arm(&mut self, a: &ast::Arm) { + self.record("Arm", Id::None, a); + ast_visit::walk_arm(self, a) + } + + fn visit_pat(&mut self, p: &ast::Pat) { + self.record("Pat", Id::None, p); + ast_visit::walk_pat(self, p) + } + + fn visit_expr(&mut self, ex: &ast::Expr) { + self.record("Expr", Id::None, ex); + ast_visit::walk_expr(self, ex) + } + + fn visit_ty(&mut self, t: &ast::Ty) { + self.record("Ty", Id::None, t); + ast_visit::walk_ty(self, t) + } + + fn visit_fn(&mut self, + fk: ast_visit::FnKind, + fd: &ast::FnDecl, + b: &ast::Block, + s: Span, + _: NodeId) { + self.record("FnDecl", Id::None, fd); + ast_visit::walk_fn(self, fk, fd, b, s) + } + + fn visit_trait_item(&mut self, ti: &ast::TraitItem) { + self.record("TraitItem", Id::None, ti); + ast_visit::walk_trait_item(self, ti) + } + + fn visit_impl_item(&mut self, ii: &ast::ImplItem) { + self.record("ImplItem", Id::None, ii); + ast_visit::walk_impl_item(self, ii) + } + + fn visit_ty_param_bound(&mut self, bounds: &ast::TyParamBound) { + self.record("TyParamBound", Id::None, bounds); + ast_visit::walk_ty_param_bound(self, bounds) + } + + fn visit_struct_field(&mut self, s: &ast::StructField) { + self.record("StructField", Id::None, s); + ast_visit::walk_struct_field(self, s) + } + + fn visit_variant(&mut self, + v: &ast::Variant, + g: &ast::Generics, + item_id: NodeId) { + self.record("Variant", Id::None, v); + ast_visit::walk_variant(self, v, g, item_id) + } + + fn visit_lifetime(&mut self, lifetime: &ast::Lifetime) { + self.record("Lifetime", Id::None, lifetime); + ast_visit::walk_lifetime(self, lifetime) + } + + fn visit_lifetime_def(&mut self, lifetime: &ast::LifetimeDef) { + self.record("LifetimeDef", Id::None, lifetime); + ast_visit::walk_lifetime_def(self, lifetime) + } + + fn visit_mac(&mut self, mac: &ast::Mac) { + self.record("Mac", Id::None, mac); + } + + fn visit_path_list_item(&mut self, + prefix: &ast::Path, + item: &ast::PathListItem) { + self.record("PathListItem", Id::None, item); + ast_visit::walk_path_list_item(self, prefix, item) + } + + fn visit_path_segment(&mut self, + path_span: Span, + path_segment: &ast::PathSegment) { + self.record("PathSegment", Id::None, path_segment); + ast_visit::walk_path_segment(self, path_span, path_segment) + } + + fn visit_assoc_type_binding(&mut self, type_binding: &ast::TypeBinding) { + self.record("TypeBinding", Id::None, type_binding); + ast_visit::walk_assoc_type_binding(self, type_binding) + } + + fn visit_attribute(&mut self, attr: &ast::Attribute) { + self.record("Attribute", Id::None, attr); + } + + fn visit_macro_def(&mut self, macro_def: &ast::MacroDef) { + self.record("MacroDef", Id::None, macro_def); + ast_visit::walk_macro_def(self, macro_def) + } +} diff --git a/src/librustc_passes/lib.rs b/src/librustc_passes/lib.rs index a4657251c9..039a76d25c 100644 --- a/src/librustc_passes/lib.rs +++ b/src/librustc_passes/lib.rs @@ -23,7 +23,7 @@ html_root_url = "https://doc.rust-lang.org/nightly/")] #![cfg_attr(not(stage0), deny(warnings))] -#![feature(dotdot_in_tuple_patterns)] +#![cfg_attr(stage0, feature(dotdot_in_tuple_patterns))] #![feature(rustc_diagnostic_macros)] #![feature(staged_api)] #![feature(rustc_private)] @@ -45,6 +45,7 @@ pub mod diagnostics; pub mod ast_validation; pub mod consts; +pub mod hir_stats; pub mod loops; pub mod no_asm; pub mod rvalues; diff --git a/src/librustc_passes/static_recursion.rs b/src/librustc_passes/static_recursion.rs index 0336c3063d..0e0f8a8456 100644 --- a/src/librustc_passes/static_recursion.rs +++ b/src/librustc_passes/static_recursion.rs @@ -14,7 +14,7 @@ use rustc::dep_graph::DepNode; use rustc::hir::map as ast_map; use rustc::session::{CompileResult, Session}; -use rustc::hir::def::{Def, DefMap}; +use rustc::hir::def::{Def, CtorKind, DefMap}; use rustc::util::nodemap::NodeMap; use syntax::ast; @@ -272,7 +272,7 @@ impl<'a, 'ast: 'a> Visitor<'ast> for CheckItemRecursionVisitor<'a, 'ast> { // affect the specific variant used, but we need to check // the whole enum definition to see what expression that // might be (if any). - Some(Def::Variant(variant_id)) => { + Some(Def::VariantCtor(variant_id, CtorKind::Const)) => { if let Some(variant_id) = self.ast_map.as_local_node_id(variant_id) { let variant = self.ast_map.expect_variant(variant_id); let enum_id = self.ast_map.get_parent(variant_id); @@ -283,7 +283,7 @@ impl<'a, 'ast: 'a> Visitor<'ast> for CheckItemRecursionVisitor<'a, 'ast> { } else { span_bug!(e.span, "`check_static_recursion` found \ - non-enum in Def::Variant"); + non-enum in Def::VariantCtor"); } } } diff --git a/src/librustc_plugin/load.rs b/src/librustc_plugin/load.rs index 9e56397bc9..4438241999 100644 --- a/src/librustc_plugin/load.rs +++ b/src/librustc_plugin/load.rs @@ -11,7 +11,7 @@ //! Used by `rustc` when loading a plugin. use rustc::session::Session; -use rustc_metadata::creader::CrateReader; +use rustc_metadata::creader::CrateLoader; use rustc_metadata::cstore::CStore; use registry::Registry; @@ -33,7 +33,7 @@ pub struct PluginRegistrar { struct PluginLoader<'a> { sess: &'a Session, - reader: CrateReader<'a>, + reader: CrateLoader<'a>, plugins: Vec, } @@ -47,7 +47,7 @@ pub fn load_plugins(sess: &Session, krate: &ast::Crate, crate_name: &str, addl_plugins: Option>) -> Vec { - let mut loader = PluginLoader::new(sess, cstore, crate_name, krate.config.clone()); + let mut loader = PluginLoader::new(sess, cstore, crate_name); // do not report any error now. since crate attributes are // not touched by expansion, every use of plugin without @@ -89,14 +89,10 @@ pub fn load_plugins(sess: &Session, } impl<'a> PluginLoader<'a> { - fn new(sess: &'a Session, - cstore: &'a CStore, - crate_name: &str, - crate_config: ast::CrateConfig) - -> PluginLoader<'a> { + fn new(sess: &'a Session, cstore: &'a CStore, crate_name: &str) -> Self { PluginLoader { sess: sess, - reader: CrateReader::new(sess, cstore, crate_name, crate_config), + reader: CrateLoader::new(sess, cstore, crate_name), plugins: vec![], } } diff --git a/src/librustc_plugin/registry.rs b/src/librustc_plugin/registry.rs index 9c74a644c3..88e248e2ef 100644 --- a/src/librustc_plugin/registry.rs +++ b/src/librustc_plugin/registry.rs @@ -73,12 +73,12 @@ impl<'a> Registry<'a> { sess: sess, args_hidden: None, krate_span: krate_span, - syntax_exts: vec!(), - early_lint_passes: vec!(), - late_lint_passes: vec!(), + syntax_exts: vec![], + early_lint_passes: vec![], + late_lint_passes: vec![], lint_groups: HashMap::new(), - llvm_passes: vec!(), - attributes: vec!(), + llvm_passes: vec![], + attributes: vec![], mir_passes: Vec::new(), } } diff --git a/src/librustc_privacy/lib.rs b/src/librustc_privacy/lib.rs index 43cdf2942d..cbe2cd2628 100644 --- a/src/librustc_privacy/lib.rs +++ b/src/librustc_privacy/lib.rs @@ -17,7 +17,7 @@ html_root_url = "https://doc.rust-lang.org/nightly/")] #![cfg_attr(not(stage0), deny(warnings))] -#![feature(dotdot_in_tuple_patterns)] +#![cfg_attr(stage0, feature(dotdot_in_tuple_patterns))] #![feature(rustc_diagnostic_macros)] #![feature(rustc_private)] #![feature(staged_api)] @@ -28,7 +28,7 @@ extern crate syntax_pos; use rustc::dep_graph::DepNode; use rustc::hir::{self, PatKind}; -use rustc::hir::def::{self, Def}; +use rustc::hir::def::{self, Def, CtorKind}; use rustc::hir::def_id::DefId; use rustc::hir::intravisit::{self, Visitor}; use rustc::hir::pat_util::EnumerateAndAdjustIterator; @@ -286,7 +286,7 @@ impl<'a, 'tcx, 'v> Visitor<'v> for EmbargoVisitor<'a, 'tcx> { if self.prev_level.is_some() { if let Some(exports) = self.export_map.get(&id) { for export in exports { - if let Some(node_id) = self.tcx.map.as_local_node_id(export.def_id) { + if let Some(node_id) = self.tcx.map.as_local_node_id(export.def.def_id()) { self.update(node_id, Some(AccessLevel::Exported)); } } @@ -430,11 +430,11 @@ impl<'a, 'tcx, 'v> Visitor<'v> for PrivacyVisitor<'a, 'tcx> { match expr.node { hir::ExprMethodCall(..) => { let method_call = ty::MethodCall::expr(expr.id); - let method = self.tcx.tables.borrow().method_map[&method_call]; + let method = self.tcx.tables().method_map[&method_call]; self.check_method(expr.span, method.def_id); } hir::ExprStruct(_, ref expr_fields, _) => { - let adt = self.tcx.expr_ty(expr).ty_adt_def().unwrap(); + let adt = self.tcx.tables().expr_ty(expr).ty_adt_def().unwrap(); let variant = adt.variant_of_def(self.tcx.expect_def(expr.id)); // RFC 736: ensure all unmentioned fields are visible. // Rather than computing the set of unmentioned fields @@ -454,36 +454,25 @@ impl<'a, 'tcx, 'v> Visitor<'v> for PrivacyVisitor<'a, 'tcx> { } } hir::ExprPath(..) => { - if let Def::Struct(..) = self.tcx.expect_def(expr.id) { - let expr_ty = self.tcx.expr_ty(expr); - let def = match expr_ty.sty { - ty::TyFnDef(.., &ty::BareFnTy { sig: ty::Binder(ty::FnSig { - output: ty, .. - }), ..}) => ty, - _ => expr_ty - }.ty_adt_def().unwrap(); - - let private_indexes : Vec<_> = def.struct_variant().fields.iter().enumerate() - .filter(|&(_,f)| { - !f.vis.is_accessible_from(self.curitem, &self.tcx.map) - }).map(|(n,&_)|n).collect(); + if let def @ Def::StructCtor(_, CtorKind::Fn) = self.tcx.expect_def(expr.id) { + let adt_def = self.tcx.expect_variant_def(def); + let private_indexes = adt_def.fields.iter().enumerate().filter(|&(_, field)| { + !field.vis.is_accessible_from(self.curitem, &self.tcx.map) + }).map(|(i, _)| i).collect::>(); if !private_indexes.is_empty() { - let mut error = struct_span_err!(self.tcx.sess, expr.span, E0450, "cannot invoke tuple struct constructor \ - with private fields"); + with private fields"); error.span_label(expr.span, &format!("cannot construct with a private field")); - if let Some(def_id) = self.tcx.map.as_local_node_id(def.did) { - if let Some(hir::map::NodeItem(node)) = self.tcx.map.find(def_id) { - if let hir::Item_::ItemStruct(ref tuple_data, _) = node.node { - - for i in private_indexes { - error.span_label(tuple_data.fields()[i].span, - &format!("private field declared here")); - } + if let Some(node_id) = self.tcx.map.as_local_node_id(adt_def.did) { + let node = self.tcx.map.find(node_id); + if let Some(hir::map::NodeStructCtor(vdata)) = node { + for i in private_indexes { + error.span_label(vdata.fields()[i].span, + &format!("private field declared here")); } } } @@ -506,14 +495,14 @@ impl<'a, 'tcx, 'v> Visitor<'v> for PrivacyVisitor<'a, 'tcx> { match pattern.node { PatKind::Struct(_, ref fields, _) => { - let adt = self.tcx.pat_ty(pattern).ty_adt_def().unwrap(); + let adt = self.tcx.tables().pat_ty(pattern).ty_adt_def().unwrap(); let variant = adt.variant_of_def(self.tcx.expect_def(pattern.id)); for field in fields { self.check_field(field.span, adt, variant.field_named(field.node.name)); } } PatKind::TupleStruct(_, ref fields, ddpos) => { - match self.tcx.pat_ty(pattern).sty { + match self.tcx.tables().pat_ty(pattern).sty { // enum fields have no privacy at this time ty::TyAdt(def, _) if !def.is_enum() => { let expected_len = def.struct_variant().fields.len(); @@ -870,9 +859,6 @@ impl<'a, 'tcx, 'v> Visitor<'v> for ObsoleteVisiblePrivateTypesVisitor<'a, 'tcx> // expression/block context can't possibly contain exported things. // (Making them no-ops stops us from traversing the whole AST without // having to be super careful about our `walk_...` calls above.) - // FIXME(#29524): Unfortunately this ^^^ is not true, blocks can contain - // exported items (e.g. impls) and actual code in rustc itself breaks - // if we don't traverse blocks in `EmbargoVisitor` fn visit_block(&mut self, _: &hir::Block) {} fn visit_expr(&mut self, _: &hir::Expr) {} } diff --git a/src/librustc_resolve/build_reduced_graph.rs b/src/librustc_resolve/build_reduced_graph.rs index 9202f8c094..d90fe769ca 100644 --- a/src/librustc_resolve/build_reduced_graph.rs +++ b/src/librustc_resolve/build_reduced_graph.rs @@ -13,6 +13,7 @@ //! Here we build the "reduced graph": the graph of the module tree without //! any imports resolved. +use macros::{InvocationData, LegacyScope}; use resolve_imports::ImportDirectiveSubclass::{self, GlobImport}; use {Module, ModuleS, ModuleKind}; use Namespace::{self, TypeNS, ValueNS}; @@ -20,21 +21,27 @@ use {NameBinding, NameBindingKind, ToNameBinding}; use Resolver; use {resolve_error, resolve_struct_error, ResolutionError}; +use rustc::middle::cstore::LoadedMacros; use rustc::hir::def::*; use rustc::hir::def_id::{CRATE_DEF_INDEX, DefId}; -use rustc::hir::map::DefPathData; use rustc::ty; +use rustc::util::nodemap::FnvHashMap; use std::cell::Cell; +use std::rc::Rc; use syntax::ast::Name; use syntax::attr; use syntax::parse::token; -use syntax::ast::{Block, Crate}; -use syntax::ast::{ForeignItem, ForeignItemKind, Item, ItemKind}; +use syntax::ast::{self, Block, ForeignItem, ForeignItemKind, Item, ItemKind}; use syntax::ast::{Mutability, StmtKind, TraitItem, TraitItemKind}; use syntax::ast::{Variant, ViewPathGlob, ViewPathList, ViewPathSimple}; +use syntax::ext::base::{SyntaxExtension, Resolver as SyntaxResolver}; +use syntax::ext::expand::mark_tts; +use syntax::ext::hygiene::Mark; +use syntax::feature_gate::{self, emit_feature_err}; +use syntax::ext::tt::macro_rules; use syntax::parse::token::keywords; use syntax::visit::{self, Visitor}; @@ -52,12 +59,15 @@ impl<'a> ToNameBinding<'a> for (Def, Span, ty::Visibility) { } } -impl<'b> Resolver<'b> { - /// Constructs the reduced graph for the entire crate. - pub fn build_reduced_graph(&mut self, krate: &Crate) { - visit::walk_crate(&mut BuildReducedGraphVisitor { resolver: self }, krate); - } +#[derive(Default, PartialEq, Eq)] +struct LegacyMacroImports { + import_all: Option, + imports: Vec<(Name, Span)>, + reexports: Vec<(Name, Span)>, + no_link: bool, +} +impl<'b> Resolver<'b> { /// Defines `name` in namespace `ns` of module `parent` to be `def` if it is not yet defined; /// otherwise, reports an error. fn define(&mut self, parent: Module<'b>, name: Name, ns: Namespace, def: T) @@ -72,15 +82,19 @@ impl<'b> Resolver<'b> { fn block_needs_anonymous_module(&mut self, block: &Block) -> bool { // If any statements are items, we need to create an anonymous module block.stmts.iter().any(|statement| match statement.node { - StmtKind::Item(_) => true, + StmtKind::Item(_) | StmtKind::Mac(_) => true, _ => false, }) } - /// Constructs the reduced graph for one item. - fn build_reduced_graph_for_item(&mut self, item: &Item) { - self.crate_loader.process_item(item, &self.definitions); + fn insert_field_names(&mut self, def_id: DefId, field_names: Vec) { + if !field_names.is_empty() { + self.field_names.insert(def_id, field_names); + } + } + /// Constructs the reduced graph for one item. + fn build_reduced_graph_for_item(&mut self, item: &Item, expansion: Mark) { let parent = self.current_module; let name = item.ident.name; let sp = item.span; @@ -91,14 +105,14 @@ impl<'b> Resolver<'b> { // Extract and intern the module part of the path. For // globs and lists, the path is found directly in the AST; // for simple paths we have to munge the path a little. - let module_path: Vec = match view_path.node { + let module_path: Vec<_> = match view_path.node { ViewPathSimple(_, ref full_path) => { full_path.segments .split_last() .unwrap() .1 .iter() - .map(|seg| seg.identifier.name) + .map(|seg| seg.identifier) .collect() } @@ -106,7 +120,7 @@ impl<'b> Resolver<'b> { ViewPathList(ref module_ident_path, _) => { module_ident_path.segments .iter() - .map(|seg| seg.identifier.name) + .map(|seg| seg.identifier) .collect() } }; @@ -116,14 +130,27 @@ impl<'b> Resolver<'b> { match view_path.node { ViewPathSimple(binding, ref full_path) => { - let source_name = full_path.segments.last().unwrap().identifier.name; - if source_name.as_str() == "mod" || source_name.as_str() == "self" { + let mut source = full_path.segments.last().unwrap().identifier; + let source_name = source.name.as_str(); + if source_name == "mod" || source_name == "self" { resolve_error(self, view_path.span, ResolutionError::SelfImportsOnlyAllowedWithin); + } else if source_name == "$crate" && full_path.segments.len() == 1 { + let crate_root = self.resolve_crate_var(source.ctxt); + let crate_name = match crate_root.kind { + ModuleKind::Def(_, name) => name, + ModuleKind::Block(..) => unreachable!(), + }; + source.name = crate_name; + + self.session.struct_span_warn(item.span, "`$crate` may not be imported") + .note("`use $crate;` was erroneously allowed and \ + will become a hard error in a future release") + .emit(); } - let subclass = ImportDirectiveSubclass::single(binding.name, source_name); + let subclass = ImportDirectiveSubclass::single(binding.name, source.name); let span = view_path.span; self.add_import_directive(module_path, subclass, span, item.id, vis); } @@ -155,7 +182,7 @@ impl<'b> Resolver<'b> { (module_path.clone(), node.name.name, rename) } else { let name = match module_path.last() { - Some(name) => *name, + Some(ident) => ident.name, None => { resolve_error( self, @@ -188,9 +215,27 @@ impl<'b> Resolver<'b> { } ItemKind::ExternCrate(_) => { - // n.b. we don't need to look at the path option here, because cstore already - // did - if let Some(crate_id) = self.session.cstore.extern_mod_stmt_cnum(item.id) { + let legacy_imports = self.legacy_macro_imports(&item.attrs); + // `#[macro_use]` and `#[macro_reexport]` are only allowed at the crate root. + if self.current_module.parent.is_some() && { + legacy_imports.import_all.is_some() || !legacy_imports.imports.is_empty() || + !legacy_imports.reexports.is_empty() + } { + if self.current_module.parent.is_some() { + span_err!(self.session, item.span, E0468, + "an `extern crate` loading macros must be at the crate root"); + } + } + + let loaded_macros = if legacy_imports != LegacyMacroImports::default() { + self.crate_loader.process_item(item, &self.definitions, true) + } else { + self.crate_loader.process_item(item, &self.definitions, false) + }; + + // n.b. we don't need to look at the path option here, because cstore already did + let crate_id = self.session.cstore.extern_mod_stmt_cnum(item.id); + let module = if let Some(crate_id) = crate_id { let def_id = DefId { krate: crate_id, index: CRATE_DEF_INDEX, @@ -201,11 +246,26 @@ impl<'b> Resolver<'b> { ..ModuleS::new(Some(parent), ModuleKind::Def(Def::Mod(def_id), name)) }); self.define(parent, name, TypeNS, (module, sp, vis)); - self.populate_module_if_necessary(module); + module + } else { + // Define an empty module + let def = Def::Mod(self.definitions.local_def_id(item.id)); + let module = ModuleS::new(Some(parent), ModuleKind::Def(def, name)); + let module = self.arenas.alloc_module(module); + self.define(parent, name, TypeNS, (module, sp, vis)); + module + }; + + if let Some(loaded_macros) = loaded_macros { + self.import_extern_crate_macros( + item, module, loaded_macros, legacy_imports, expansion == Mark::root(), + ); } } + ItemKind::Mod(..) if item.ident == keywords::Invalid.ident() => {} // Crate root + ItemKind::Mod(..) => { let def = Def::Mod(self.definitions.local_def_id(item.id)); let module = self.arenas.alloc_module(ModuleS { @@ -222,7 +282,9 @@ impl<'b> Resolver<'b> { self.current_module = module; } - ItemKind::ForeignMod(..) => {} + ItemKind::ForeignMod(..) => { + self.crate_loader.process_item(item, &self.definitions, false); + } // These items live in the value namespace. ItemKind::Static(_, m, _) => { @@ -264,32 +326,31 @@ impl<'b> Resolver<'b> { // If this is a tuple or unit struct, define a name // in the value namespace as well. if !struct_def.is_struct() { - let def = Def::Struct(self.definitions.local_def_id(struct_def.id())); - self.define(parent, name, ValueNS, (def, sp, vis)); + let ctor_def = Def::StructCtor(self.definitions.local_def_id(struct_def.id()), + CtorKind::from_ast(struct_def)); + self.define(parent, name, ValueNS, (ctor_def, sp, vis)); } - // Record the def ID and fields of this struct. - let field_names = struct_def.fields().iter().enumerate().map(|(index, field)| { + // Record field names for error reporting. + let field_names = struct_def.fields().iter().filter_map(|field| { self.resolve_visibility(&field.vis); field.ident.map(|ident| ident.name) - .unwrap_or_else(|| token::intern(&index.to_string())) }).collect(); let item_def_id = self.definitions.local_def_id(item.id); - self.structs.insert(item_def_id, field_names); + self.insert_field_names(item_def_id, field_names); } ItemKind::Union(ref vdata, _) => { let def = Def::Union(self.definitions.local_def_id(item.id)); self.define(parent, name, TypeNS, (def, sp, vis)); - // Record the def ID and fields of this union. - let field_names = vdata.fields().iter().enumerate().map(|(index, field)| { + // Record field names for error reporting. + let field_names = vdata.fields().iter().filter_map(|field| { self.resolve_visibility(&field.vis); field.ident.map(|ident| ident.name) - .unwrap_or_else(|| token::intern(&index.to_string())) }).collect(); let item_def_id = self.definitions.local_def_id(item.id); - self.structs.insert(item_def_id, field_names); + self.insert_field_names(item_def_id, field_names); } ItemKind::DefaultImpl(..) | ItemKind::Impl(..) => {} @@ -314,17 +375,18 @@ impl<'b> Resolver<'b> { parent: Module<'b>, vis: ty::Visibility) { let name = variant.node.name.name; - if variant.node.data.is_struct() { - // Not adding fields for variants as they are not accessed with a self receiver - let variant_def_id = self.definitions.local_def_id(variant.node.data.id()); - self.structs.insert(variant_def_id, Vec::new()); - } + let def_id = self.definitions.local_def_id(variant.node.data.id()); - // Variants are always treated as importable to allow them to be glob used. - // All variants are defined in both type and value namespaces as future-proofing. - let def = Def::Variant(self.definitions.local_def_id(variant.node.data.id())); - self.define(parent, name, ValueNS, (def, variant.span, vis)); + // Define a name in the type namespace. + let def = Def::Variant(def_id); self.define(parent, name, TypeNS, (def, variant.span, vis)); + + // Define a constructor name in the value namespace. + // Braced variants, unlike structs, generate unusable names in + // value namespace, they are reserved for possible future use. + let ctor_kind = CtorKind::from_ast(&variant.node.data); + let ctor_def = Def::VariantCtor(def_id, ctor_kind); + self.define(parent, name, ValueNS, (ctor_def, variant.span, vis)); } /// Constructs the reduced graph for one foreign item. @@ -362,15 +424,9 @@ impl<'b> Resolver<'b> { /// Builds the reduced graph for a single item in an external crate. fn build_reduced_graph_for_external_crate_def(&mut self, parent: Module<'b>, child: Export) { - let def_id = child.def_id; let name = child.name; - - let def = if let Some(def) = self.session.cstore.describe_def(def_id) { - def - } else { - return; - }; - + let def = child.def; + let def_id = def.def_id(); let vis = if parent.is_trait() { ty::Visibility::Public } else { @@ -378,83 +434,56 @@ impl<'b> Resolver<'b> { }; match def { - Def::Mod(_) | Def::Enum(..) => { - debug!("(building reduced graph for external crate) building module {} {:?}", - name, vis); + Def::Mod(..) | Def::Enum(..) => { let module = self.new_module(parent, ModuleKind::Def(def, name), false); - let _ = self.try_define(parent, name, TypeNS, (module, DUMMY_SP, vis)); - } - Def::Variant(variant_id) => { - debug!("(building reduced graph for external crate) building variant {}", name); - // Variants are always treated as importable to allow them to be glob used. - // All variants are defined in both type and value namespaces as future-proofing. - let _ = self.try_define(parent, name, TypeNS, (def, DUMMY_SP, vis)); - let _ = self.try_define(parent, name, ValueNS, (def, DUMMY_SP, vis)); - if self.session.cstore.variant_kind(variant_id) == Some(ty::VariantKind::Struct) { - // Not adding fields for variants as they are not accessed with a self receiver - self.structs.insert(variant_id, Vec::new()); - } + self.define(parent, name, TypeNS, (module, DUMMY_SP, vis)); + } + Def::Variant(..) => { + self.define(parent, name, TypeNS, (def, DUMMY_SP, vis)); + } + Def::VariantCtor(..) => { + self.define(parent, name, ValueNS, (def, DUMMY_SP, vis)); } Def::Fn(..) | Def::Static(..) | Def::Const(..) | Def::AssociatedConst(..) | Def::Method(..) => { - debug!("(building reduced graph for external crate) building value (fn/static) {}", - name); - let _ = self.try_define(parent, name, ValueNS, (def, DUMMY_SP, vis)); + self.define(parent, name, ValueNS, (def, DUMMY_SP, vis)); } - Def::Trait(_) => { - debug!("(building reduced graph for external crate) building type {}", name); - - // If this is a trait, add all the trait item names to the trait - // info. + Def::Trait(..) => { + let module = self.new_module(parent, ModuleKind::Def(def, name), false); + self.define(parent, name, TypeNS, (module, DUMMY_SP, vis)); + // If this is a trait, add all the trait item names to the trait info. let trait_item_def_ids = self.session.cstore.impl_or_trait_items(def_id); - for &trait_item_def in &trait_item_def_ids { - let trait_item_name = - self.session.cstore.def_key(trait_item_def) - .disambiguated_data.data.get_opt_name() - .expect("opt_item_name returned None for trait"); - - debug!("(building reduced graph for external crate) ... adding trait item \ - '{}'", - trait_item_name); - + for trait_item_def_id in trait_item_def_ids { + let trait_item_name = self.session.cstore.def_key(trait_item_def_id) + .disambiguated_data.data.get_opt_name() + .expect("opt_item_name returned None for trait"); self.trait_item_map.insert((trait_item_name, def_id), false); } - - let module = self.new_module(parent, ModuleKind::Def(def, name), false); - let _ = self.try_define(parent, name, TypeNS, (module, DUMMY_SP, vis)); } Def::TyAlias(..) | Def::AssociatedTy(..) => { - debug!("(building reduced graph for external crate) building type {}", name); - let _ = self.try_define(parent, name, TypeNS, (def, DUMMY_SP, vis)); - } - Def::Struct(_) - if self.session.cstore.def_key(def_id).disambiguated_data.data != - DefPathData::StructCtor - => { - debug!("(building reduced graph for external crate) building type and value for {}", - name); - let _ = self.try_define(parent, name, TypeNS, (def, DUMMY_SP, vis)); - if let Some(ctor_def_id) = self.session.cstore.struct_ctor_def_id(def_id) { - let def = Def::Struct(ctor_def_id); - let _ = self.try_define(parent, name, ValueNS, (def, DUMMY_SP, vis)); - } + self.define(parent, name, TypeNS, (def, DUMMY_SP, vis)); + } + Def::Struct(..) => { + self.define(parent, name, TypeNS, (def, DUMMY_SP, vis)); - // Record the def ID and fields of this struct. - let fields = self.session.cstore.struct_field_names(def_id); - self.structs.insert(def_id, fields); + // Record field names for error reporting. + let field_names = self.session.cstore.struct_field_names(def_id); + self.insert_field_names(def_id, field_names); + } + Def::StructCtor(..) => { + self.define(parent, name, ValueNS, (def, DUMMY_SP, vis)); } - Def::Union(_) => { - let _ = self.try_define(parent, name, TypeNS, (def, DUMMY_SP, vis)); + Def::Union(..) => { + self.define(parent, name, TypeNS, (def, DUMMY_SP, vis)); - // Record the def ID and fields of this union. - let fields = self.session.cstore.struct_field_names(def_id); - self.structs.insert(def_id, fields); + // Record field names for error reporting. + let field_names = self.session.cstore.struct_field_names(def_id); + self.insert_field_names(def_id, field_names); } - Def::Struct(..) => {} Def::Local(..) | Def::PrimTy(..) | Def::TyParam(..) | @@ -462,7 +491,7 @@ impl<'b> Resolver<'b> { Def::Label(..) | Def::SelfTy(..) | Def::Err => { - bug!("didn't expect `{:?}`", def); + bug!("unexpected definition: {:?}", def); } } } @@ -476,35 +505,238 @@ impl<'b> Resolver<'b> { } module.populated.set(true) } + + fn import_extern_crate_macros(&mut self, + extern_crate: &Item, + module: Module<'b>, + loaded_macros: LoadedMacros, + legacy_imports: LegacyMacroImports, + allow_shadowing: bool) { + let import_macro = |this: &mut Self, name, ext: Rc<_>, span| { + this.used_crates.insert(module.def_id().unwrap().krate); + if let SyntaxExtension::NormalTT(..) = *ext { + this.macro_names.insert(name); + } + if this.builtin_macros.insert(name, ext).is_some() && !allow_shadowing { + let msg = format!("`{}` is already in scope", name); + let note = + "macro-expanded `#[macro_use]`s may not shadow existing macros (see RFC 1560)"; + this.session.struct_span_err(span, &msg).note(note).emit(); + } + }; + + match loaded_macros { + LoadedMacros::MacroRules(macros) => { + let mark = Mark::fresh(); + if !macros.is_empty() { + let invocation = self.arenas.alloc_invocation_data(InvocationData { + module: Cell::new(module), + def_index: CRATE_DEF_INDEX, + const_integer: false, + legacy_scope: Cell::new(LegacyScope::Empty), + expansion: Cell::new(LegacyScope::Empty), + }); + self.invocations.insert(mark, invocation); + } + + let mut macros: FnvHashMap<_, _> = macros.into_iter().map(|mut def| { + def.body = mark_tts(&def.body, mark); + let ext = macro_rules::compile(&self.session.parse_sess, &def); + (def.ident.name, (def, Rc::new(ext))) + }).collect(); + + if let Some(span) = legacy_imports.import_all { + for (&name, &(_, ref ext)) in macros.iter() { + import_macro(self, name, ext.clone(), span); + } + } else { + for (name, span) in legacy_imports.imports { + if let Some(&(_, ref ext)) = macros.get(&name) { + import_macro(self, name, ext.clone(), span); + } else { + span_err!(self.session, span, E0469, "imported macro not found"); + } + } + } + for (name, span) in legacy_imports.reexports { + if let Some((mut def, _)) = macros.remove(&name) { + def.id = self.next_node_id(); + self.exported_macros.push(def); + } else { + span_err!(self.session, span, E0470, "reexported macro not found"); + } + } + } + + LoadedMacros::ProcMacros(macros) => { + if !self.session.features.borrow().proc_macro { + let sess = &self.session.parse_sess; + let issue = feature_gate::GateIssue::Language; + let msg = + "loading custom derive macro crates is experimentally supported"; + emit_feature_err(sess, "proc_macro", extern_crate.span, issue, msg); + } + if !legacy_imports.imports.is_empty() { + let msg = "`proc-macro` crates cannot be selectively imported from, \ + must use `#[macro_use]`"; + self.session.span_err(extern_crate.span, msg); + } + if !legacy_imports.reexports.is_empty() { + let msg = "`proc-macro` crates cannot be reexported from"; + self.session.span_err(extern_crate.span, msg); + } + if let Some(span) = legacy_imports.import_all { + for (name, ext) in macros { + import_macro(self, name, Rc::new(ext), span); + } + } + } + } + } + + // does this attribute list contain "macro_use"? + fn contains_macro_use(&mut self, attrs: &[ast::Attribute]) -> bool { + for attr in attrs { + if attr.check_name("macro_escape") { + let msg = "macro_escape is a deprecated synonym for macro_use"; + let mut err = self.session.struct_span_warn(attr.span, msg); + if let ast::AttrStyle::Inner = attr.node.style { + err.help("consider an outer attribute, #[macro_use] mod ...").emit(); + } else { + err.emit(); + } + } else if !attr.check_name("macro_use") { + continue; + } + + if !attr.is_word() { + self.session.span_err(attr.span, "arguments to macro_use are not allowed here"); + } + return true; + } + + false + } + + fn legacy_macro_imports(&mut self, attrs: &[ast::Attribute]) -> LegacyMacroImports { + let mut imports = LegacyMacroImports::default(); + for attr in attrs { + if attr.check_name("macro_use") { + match attr.meta_item_list() { + Some(names) => for attr in names { + if let Some(word) = attr.word() { + imports.imports.push((token::intern(&word.name()), attr.span())); + } else { + span_err!(self.session, attr.span(), E0466, "bad macro import"); + } + }, + None => imports.import_all = Some(attr.span), + } + } else if attr.check_name("macro_reexport") { + let bad_macro_reexport = |this: &mut Self, span| { + span_err!(this.session, span, E0467, "bad macro reexport"); + }; + if let Some(names) = attr.meta_item_list() { + for attr in names { + if let Some(word) = attr.word() { + imports.reexports.push((token::intern(&word.name()), attr.span())); + } else { + bad_macro_reexport(self, attr.span()); + } + } + } else { + bad_macro_reexport(self, attr.span()); + } + } else if attr.check_name("no_link") { + imports.no_link = true; + } + } + imports + } } -struct BuildReducedGraphVisitor<'a, 'b: 'a> { - resolver: &'a mut Resolver<'b>, +pub struct BuildReducedGraphVisitor<'a, 'b: 'a> { + pub resolver: &'a mut Resolver<'b>, + pub legacy_scope: LegacyScope<'b>, + pub expansion: Mark, +} + +impl<'a, 'b> BuildReducedGraphVisitor<'a, 'b> { + fn visit_invoc(&mut self, id: ast::NodeId) -> &'b InvocationData<'b> { + let invocation = self.resolver.invocations[&Mark::from_placeholder_id(id)]; + invocation.module.set(self.resolver.current_module); + invocation.legacy_scope.set(self.legacy_scope); + invocation + } +} + +macro_rules! method { + ($visit:ident: $ty:ty, $invoc:path, $walk:ident) => { + fn $visit(&mut self, node: &$ty) { + if let $invoc(..) = node.node { + self.visit_invoc(node.id); + } else { + visit::$walk(self, node); + } + } + } } impl<'a, 'b> Visitor for BuildReducedGraphVisitor<'a, 'b> { + method!(visit_impl_item: ast::ImplItem, ast::ImplItemKind::Macro, walk_impl_item); + method!(visit_expr: ast::Expr, ast::ExprKind::Mac, walk_expr); + method!(visit_pat: ast::Pat, ast::PatKind::Mac, walk_pat); + method!(visit_ty: ast::Ty, ast::TyKind::Mac, walk_ty); + fn visit_item(&mut self, item: &Item) { - let parent = self.resolver.current_module; - self.resolver.build_reduced_graph_for_item(item); + let macro_use = match item.node { + ItemKind::Mac(..) if item.id == ast::DUMMY_NODE_ID => return, // Scope placeholder + ItemKind::Mac(..) => { + return self.legacy_scope = LegacyScope::Expansion(self.visit_invoc(item.id)); + } + ItemKind::Mod(..) => self.resolver.contains_macro_use(&item.attrs), + _ => false, + }; + + let (parent, legacy_scope) = (self.resolver.current_module, self.legacy_scope); + self.resolver.build_reduced_graph_for_item(item, self.expansion); visit::walk_item(self, item); self.resolver.current_module = parent; + if !macro_use { + self.legacy_scope = legacy_scope; + } + } + + fn visit_stmt(&mut self, stmt: &ast::Stmt) { + if let ast::StmtKind::Mac(..) = stmt.node { + self.legacy_scope = LegacyScope::Expansion(self.visit_invoc(stmt.id)); + } else { + visit::walk_stmt(self, stmt); + } } fn visit_foreign_item(&mut self, foreign_item: &ForeignItem) { self.resolver.build_reduced_graph_for_foreign_item(foreign_item); + visit::walk_foreign_item(self, foreign_item); } fn visit_block(&mut self, block: &Block) { - let parent = self.resolver.current_module; + let (parent, legacy_scope) = (self.resolver.current_module, self.legacy_scope); self.resolver.build_reduced_graph_for_block(block); visit::walk_block(self, block); self.resolver.current_module = parent; + self.legacy_scope = legacy_scope; } fn visit_trait_item(&mut self, item: &TraitItem) { let parent = self.resolver.current_module; let def_id = parent.def_id().unwrap(); + if let TraitItemKind::Macro(_) = item.node { + self.visit_invoc(item.id); + return + } + // Add the item to the trait info. let item_def_id = self.resolver.definitions.local_def_id(item.id); let mut is_static_method = false; @@ -515,7 +747,7 @@ impl<'a, 'b> Visitor for BuildReducedGraphVisitor<'a, 'b> { (Def::Method(item_def_id), ValueNS) } TraitItemKind::Type(..) => (Def::AssociatedTy(item_def_id), TypeNS), - TraitItemKind::Macro(_) => panic!("unexpanded macro in resolve!"), + TraitItemKind::Macro(_) => bug!(), // handled above }; self.resolver.trait_item_map.insert((item.ident.name, def_id), is_static_method); diff --git a/src/librustc_resolve/check_unused.rs b/src/librustc_resolve/check_unused.rs index 93abe07128..e1ea40809d 100644 --- a/src/librustc_resolve/check_unused.rs +++ b/src/librustc_resolve/check_unused.rs @@ -59,10 +59,12 @@ impl<'a, 'b> UnusedImportCheckVisitor<'a, 'b> { // Check later. return; } - self.session.add_lint(lint::builtin::UNUSED_IMPORTS, - id, - span, - "unused import".to_string()); + let msg = if let Ok(snippet) = self.session.codemap().span_to_snippet(span) { + format!("unused import: `{}`", snippet) + } else { + "unused import".to_string() + }; + self.session.add_lint(lint::builtin::UNUSED_IMPORTS, id, span, msg); } else { // This trait import is definitely used, in a way other than // method resolution. diff --git a/src/librustc_resolve/diagnostics.rs b/src/librustc_resolve/diagnostics.rs index f8f90bdb4e..5eb269030a 100644 --- a/src/librustc_resolve/diagnostics.rs +++ b/src/librustc_resolve/diagnostics.rs @@ -860,31 +860,6 @@ match (A, B, C) { ``` "##, -E0422: r##" -You are trying to use an identifier that is either undefined or not a struct. - -Erroneous code example: - -``` compile_fail,E0422 -fn main () { - let x = Foo { x: 1, y: 2 }; -} -``` - -In this case, `Foo` is undefined, so it inherently isn't anything, and -definitely not a struct. - -```compile_fail,E0422 -fn main () { - let foo = 1; - let x = foo { x: 1, y: 2 }; -} -``` - -In this case, `foo` is defined, but is not a struct, so Rust can't use it as -one. -"##, - E0423: r##" A `struct` variant name was used like a function name. @@ -1272,6 +1247,185 @@ impl Foo for i32 {} ``` "##, +E0466: r##" +Macro import declarations were malformed. + +Erroneous code examples: + +```compile_fail,E0466 +#[macro_use(a_macro(another_macro))] // error: invalid import declaration +extern crate core as some_crate; + +#[macro_use(i_want = "some_macros")] // error: invalid import declaration +extern crate core as another_crate; +``` + +This is a syntax error at the level of attribute declarations. The proper +syntax for macro imports is the following: + +```ignore +// In some_crate: +#[macro_export] +macro_rules! get_tacos { + ... +} + +#[macro_export] +macro_rules! get_pimientos { + ... +} + +// In your crate: +#[macro_use(get_tacos, get_pimientos)] // It imports `get_tacos` and +extern crate some_crate; // `get_pimientos` macros from some_crate +``` + +If you would like to import all exported macros, write `macro_use` with no +arguments. +"##, + +E0467: r##" +Macro reexport declarations were empty or malformed. + +Erroneous code examples: + +```compile_fail,E0467 +#[macro_reexport] // error: no macros listed for export +extern crate core as macros_for_good; + +#[macro_reexport(fun_macro = "foo")] // error: not a macro identifier +extern crate core as other_macros_for_good; +``` + +This is a syntax error at the level of attribute declarations. + +Currently, `macro_reexport` requires at least one macro name to be listed. +Unlike `macro_use`, listing no names does not reexport all macros from the +given crate. + +Decide which macros you would like to export and list them properly. + +These are proper reexport declarations: + +```ignore +#[macro_reexport(some_macro, another_macro)] +extern crate macros_for_good; +``` +"##, + +E0468: r##" +A non-root module attempts to import macros from another crate. + +Example of erroneous code: + +```compile_fail,E0468 +mod foo { + #[macro_use(helpful_macro)] // error: must be at crate root to import + extern crate core; // macros from another crate + helpful_macro!(...); +} +``` + +Only `extern crate` imports at the crate root level are allowed to import +macros. + +Either move the macro import to crate root or do without the foreign macros. +This will work: + +```ignore +#[macro_use(helpful_macro)] +extern crate some_crate; + +mod foo { + helpful_macro!(...) +} +``` +"##, + +E0469: r##" +A macro listed for import was not found. + +Erroneous code example: + +```compile_fail,E0469 +#[macro_use(drink, be_merry)] // error: imported macro not found +extern crate collections; + +fn main() { + // ... +} +``` + +Either the listed macro is not contained in the imported crate, or it is not +exported from the given crate. + +This could be caused by a typo. Did you misspell the macro's name? + +Double-check the names of the macros listed for import, and that the crate +in question exports them. + +A working version would be: + +```ignore +// In some_crate crate: +#[macro_export] +macro_rules! eat { + ... +} + +#[macro_export] +macro_rules! drink { + ... +} + +// In your crate: +#[macro_use(eat, drink)] +extern crate some_crate; //ok! +``` +"##, + +E0470: r##" +A macro listed for reexport was not found. + +Erroneous code example: + +```compile_fail,E0470 +#[macro_reexport(drink, be_merry)] +extern crate collections; + +fn main() { + // ... +} +``` + +Either the listed macro is not contained in the imported crate, or it is not +exported from the given crate. + +This could be caused by a typo. Did you misspell the macro's name? + +Double-check the names of the macros listed for reexport, and that the crate +in question exports them. + +A working version: + +```ignore +// In some_crate crate: +#[macro_export] +macro_rules! eat { + ... +} + +#[macro_export] +macro_rules! drink { + ... +} + +// In your_crate: +#[macro_reexport(eat, drink)] +extern crate some_crate; +``` +"##, + E0530: r##" A binding shadowed something it shouldn't. @@ -1307,6 +1461,47 @@ match r { ``` "##, +E0532: r##" +Pattern arm did not match expected kind. + +Erroneous code example: + +```compile_fail,E0532 +enum State { + Succeeded, + Failed(String), +} + +fn print_on_failure(state: &State) { + match *state { + // error: expected unit struct/variant or constant, found tuple + // variant `State::Failed` + State::Failed => println!("Failed"), + _ => () + } +} +``` + +To fix this error, ensure the match arm kind is the same as the expression +matched. + +Fixed example: + +``` +enum State { + Succeeded, + Failed(String), +} + +fn print_on_failure(state: &State) { + match *state { + State::Failed(ref msg) => println!("Failed with {}", msg), + _ => () + } +} +``` +"##, + } register_diagnostics! { @@ -1324,7 +1519,7 @@ register_diagnostics! { // E0419, merged into 531 // E0420, merged into 532 // E0421, merged into 531 +// E0422, merged into 531/532 E0531, // unresolved pattern path kind `name` - E0532, // expected pattern path kind, found another pattern path kind // E0427, merged into 530 } diff --git a/src/librustc_resolve/lib.rs b/src/librustc_resolve/lib.rs index 798614ce58..fc632298c0 100644 --- a/src/librustc_resolve/lib.rs +++ b/src/librustc_resolve/lib.rs @@ -19,7 +19,7 @@ #![feature(associated_consts)] #![feature(borrow_state)] -#![feature(dotdot_in_tuple_patterns)] +#![cfg_attr(stage0, feature(dotdot_in_tuple_patterns))] #![feature(rustc_diagnostic_macros)] #![feature(rustc_private)] #![feature(staged_api)] @@ -42,7 +42,7 @@ use self::RibKind::*; use self::UseLexicalScopeFlag::*; use self::ModulePrefixResult::*; -use rustc::hir::map::Definitions; +use rustc::hir::map::{Definitions, DefCollector}; use rustc::hir::{self, PrimTy, TyBool, TyChar, TyFloat, TyInt, TyUint, TyStr}; use rustc::middle::cstore::CrateLoader; use rustc::session::Session; @@ -53,10 +53,10 @@ use rustc::ty; use rustc::hir::{Freevar, FreevarMap, TraitCandidate, TraitMap, GlobMap}; use rustc::util::nodemap::{NodeMap, NodeSet, FnvHashMap, FnvHashSet}; -use syntax::ext::base::MultiItemModifier; -use syntax::ext::hygiene::Mark; +use syntax::ext::hygiene::{Mark, SyntaxContext}; use syntax::ast::{self, FloatTy}; -use syntax::ast::{CRATE_NODE_ID, Name, NodeId, SpannedIdent, IntTy, UintTy}; +use syntax::ast::{CRATE_NODE_ID, Name, NodeId, Ident, SpannedIdent, IntTy, UintTy}; +use syntax::ext::base::SyntaxExtension; use syntax::parse::token::{self, keywords}; use syntax::util::lev_distance::find_best_match_for_name; @@ -72,11 +72,12 @@ use syntax_pos::{Span, DUMMY_SP}; use errors::DiagnosticBuilder; use std::cell::{Cell, RefCell}; -use std::rc::Rc; use std::fmt; use std::mem::replace; +use std::rc::Rc; use resolve_imports::{ImportDirective, NameResolution}; +use macros::{InvocationData, LegacyBinding, LegacyScope}; // NB: This module needs to be declared first so diagnostics are // registered before they are used. @@ -128,8 +129,6 @@ enum ResolutionError<'a> { IdentifierBoundMoreThanOnceInParameterList(&'a str), /// error E0416: identifier is bound more than once in the same pattern IdentifierBoundMoreThanOnceInSamePattern(&'a str), - /// error E0422: does not name a struct - DoesNotNameAStruct(&'a str), /// error E0423: is a struct variant name, but this expression uses it like a function name StructVariantUsedAsFunction(&'a str), /// error E0424: `self` is not available in a static method @@ -274,13 +273,15 @@ fn resolve_struct_error<'b, 'a: 'b, 'c>(resolver: &'b Resolver<'a>, err } ResolutionError::VariableNotBoundInPattern(variable_name, from, to) => { - struct_span_err!(resolver.session, + let mut err = struct_span_err!(resolver.session, span, E0408, "variable `{}` from pattern #{} is not bound in pattern #{}", variable_name, from, - to) + to); + err.span_label(span, &format!("pattern doesn't bind `{}`", variable_name)); + err } ResolutionError::VariableBoundWithDifferentMode(variable_name, pattern_number, @@ -333,15 +334,6 @@ fn resolve_struct_error<'b, 'a: 'b, 'c>(resolver: &'b Resolver<'a>, err.span_label(span, &format!("used in a pattern more than once")); err } - ResolutionError::DoesNotNameAStruct(name) => { - let mut err = struct_span_err!(resolver.session, - span, - E0422, - "`{}` does not name a structure", - name); - err.span_label(span, &format!("not a structure")); - err - } ResolutionError::StructVariantUsedAsFunction(path_name) => { let mut err = struct_span_err!(resolver.session, span, @@ -485,7 +477,7 @@ fn resolve_struct_error<'b, 'a: 'b, 'c>(resolver: &'b Resolver<'a>, E0531, "unresolved {} `{}`", expected_what, - path.segments.last().unwrap().identifier) + path) } ResolutionError::PatPathUnexpected(expected_what, found_what, path) => { struct_span_err!(resolver.session, @@ -494,7 +486,7 @@ fn resolve_struct_error<'b, 'a: 'b, 'c>(resolver: &'b Resolver<'a>, "expected {}, found {} `{}`", expected_what, found_what, - path.segments.last().unwrap().identifier) + path) } } } @@ -506,7 +498,7 @@ struct BindingInfo { } // Map from the name in a pattern to its binding mode. -type BindingMap = FnvHashMap; +type BindingMap = FnvHashMap; #[derive(Copy, Clone, PartialEq, Eq, Debug)] enum PatternSource { @@ -711,7 +703,7 @@ enum ModulePrefixResult<'a> { /// One local scope. #[derive(Debug)] struct Rib<'a> { - bindings: FnvHashMap, + bindings: FnvHashMap, kind: RibKind<'a>, } @@ -842,6 +834,10 @@ impl<'a> ModuleS<'a> { _ => false, } } + + fn is_local(&self) -> bool { + self.normal_ancestor_id.is_some() + } } impl<'a> fmt::Debug for ModuleS<'a> { @@ -919,7 +915,8 @@ impl<'a> NameBinding<'a> { fn is_variant(&self) -> bool { match self.kind { - NameBindingKind::Def(Def::Variant(..)) => true, + NameBindingKind::Def(Def::Variant(..)) | + NameBindingKind::Def(Def::VariantCtor(..)) => true, _ => false, } } @@ -1000,7 +997,9 @@ pub struct Resolver<'a> { trait_item_map: FnvHashMap<(Name, DefId), bool /* is static method? */>, - structs: FnvHashMap>, + // Names of fields of an item `DefId` accessible with dot syntax. + // Used for hints during error reporting. + field_names: FnvHashMap>, // All imports known to succeed or fail. determined_imports: Vec<&'a ImportDirective<'a>>, @@ -1068,18 +1067,20 @@ pub struct Resolver<'a> { privacy_errors: Vec>, ambiguity_errors: Vec>, + disallowed_shadowing: Vec<&'a LegacyBinding<'a>>, arenas: &'a ResolverArenas<'a>, dummy_binding: &'a NameBinding<'a>, new_import_semantics: bool, // true if `#![feature(item_like_imports)]` pub exported_macros: Vec, - pub derive_modes: FnvHashMap>, crate_loader: &'a mut CrateLoader, macro_names: FnvHashSet, + builtin_macros: FnvHashMap>, + lexical_macro_resolutions: Vec<(Name, LegacyScope<'a>)>, // Maps the `Mark` of an expansion to its containing module or block. - expansion_data: FnvHashMap, + invocations: FnvHashMap>, } pub struct ResolverArenas<'a> { @@ -1088,6 +1089,8 @@ pub struct ResolverArenas<'a> { name_bindings: arena::TypedArena>, import_directives: arena::TypedArena>, name_resolutions: arena::TypedArena>>, + invocation_data: arena::TypedArena>, + legacy_bindings: arena::TypedArena>, } impl<'a> ResolverArenas<'a> { @@ -1111,6 +1114,13 @@ impl<'a> ResolverArenas<'a> { fn alloc_name_resolution(&'a self) -> &'a RefCell> { self.name_resolutions.alloc(Default::default()) } + fn alloc_invocation_data(&'a self, expansion_data: InvocationData<'a>) + -> &'a InvocationData<'a> { + self.invocation_data.alloc(expansion_data) + } + fn alloc_legacy_binding(&'a self, binding: LegacyBinding<'a>) -> &'a LegacyBinding<'a> { + self.legacy_bindings.alloc(binding) + } } impl<'a> ty::NodeIdTree for Resolver<'a> { @@ -1162,18 +1172,18 @@ impl<'a> hir::lowering::Resolver for Resolver<'a> { } trait Named { - fn name(&self) -> Name; + fn ident(&self) -> Ident; } impl Named for ast::PathSegment { - fn name(&self) -> Name { - self.identifier.name + fn ident(&self) -> Ident { + self.identifier } } impl Named for hir::PathSegment { - fn name(&self) -> Name { - self.name + fn ident(&self) -> Ident { + Ident::with_empty_ctxt(self.name) } } @@ -1193,13 +1203,17 @@ impl<'a> Resolver<'a> { let mut module_map = NodeMap(); module_map.insert(CRATE_NODE_ID, graph_root); - let mut expansion_data = FnvHashMap(); - expansion_data.insert(0, macros::ExpansionData::default()); // Crate root expansion + let mut definitions = Definitions::new(); + DefCollector::new(&mut definitions).collect_root(); + + let mut invocations = FnvHashMap(); + invocations.insert(Mark::root(), + arenas.alloc_invocation_data(InvocationData::root(graph_root))); Resolver { session: session, - definitions: Definitions::new(), + definitions: definitions, macros_at_scope: FnvHashMap(), // The outermost module has def ID 0; this is not reflected in the @@ -1208,7 +1222,7 @@ impl<'a> Resolver<'a> { prelude: None, trait_item_map: FnvHashMap(), - structs: FnvHashMap(), + field_names: FnvHashMap(), determined_imports: Vec::new(), indeterminate_imports: Vec::new(), @@ -1240,6 +1254,7 @@ impl<'a> Resolver<'a> { privacy_errors: Vec::new(), ambiguity_errors: Vec::new(), + disallowed_shadowing: Vec::new(), arenas: arenas, dummy_binding: arenas.alloc_name_binding(NameBinding { @@ -1250,10 +1265,11 @@ impl<'a> Resolver<'a> { new_import_semantics: session.features.borrow().item_like_imports, exported_macros: Vec::new(), - derive_modes: FnvHashMap(), crate_loader: crate_loader, macro_names: FnvHashSet(), - expansion_data: expansion_data, + builtin_macros: FnvHashMap(), + lexical_macro_resolutions: Vec::new(), + invocations: invocations, } } @@ -1264,11 +1280,20 @@ impl<'a> Resolver<'a> { name_bindings: arena::TypedArena::new(), import_directives: arena::TypedArena::new(), name_resolutions: arena::TypedArena::new(), + invocation_data: arena::TypedArena::new(), + legacy_bindings: arena::TypedArena::new(), } } /// Entry point to crate resolution. pub fn resolve_crate(&mut self, krate: &Crate) { + // Collect `DefId`s for exported macro defs. + for def in &krate.exported_macros { + DefCollector::new(&mut self.definitions).with_parent(CRATE_DEF_INDEX, |collector| { + collector.visit_macro_def(def) + }) + } + self.current_module = self.graph_root; visit::walk_crate(self, krate); @@ -1334,7 +1359,7 @@ impl<'a> Resolver<'a> { /// Resolves the given module path from the given root `search_module`. fn resolve_module_path_from_root(&mut self, mut search_module: Module<'a>, - module_path: &[Name], + module_path: &[Ident], index: usize, span: Option) -> ResolveResult> { @@ -1357,7 +1382,7 @@ impl<'a> Resolver<'a> { // upward though scope chains; we simply resolve names directly in // modules as we go. while index < module_path_len { - let name = module_path[index]; + let name = module_path[index].name; match self.resolve_name_in_module(search_module, name, TypeNS, false, span) { Failed(_) => { let segment_name = name.as_str(); @@ -1378,7 +1403,7 @@ impl<'a> Resolver<'a> { format!("Did you mean `{}{}`?", prefix, path_str) } - None => format!("Maybe a missing `extern crate {}`?", segment_name), + None => format!("Maybe a missing `extern crate {};`?", segment_name), } } else { format!("Could not find `{}` in `{}`", segment_name, module_name) @@ -1411,7 +1436,7 @@ impl<'a> Resolver<'a> { /// Attempts to resolve the module part of an import directive or path /// rooted at the given module. fn resolve_module_path(&mut self, - module_path: &[Name], + module_path: &[Ident], use_lexical_scope: UseLexicalScopeFlag, span: Option) -> ResolveResult> { @@ -1449,7 +1474,7 @@ impl<'a> Resolver<'a> { // This is not a crate-relative path. We resolve the // first component of the path in the current lexical // scope and then proceed to resolve below that. - let ident = ast::Ident::with_empty_ctxt(module_path[0]); + let ident = module_path[0]; let lexical_binding = self.resolve_ident_in_lexical_scope(ident, TypeNS, span); if let Some(binding) = lexical_binding.and_then(LexicalScopeBinding::item) { @@ -1495,12 +1520,12 @@ impl<'a> Resolver<'a> { /// Invariant: This must only be called during main resolution, not during /// import resolution. fn resolve_ident_in_lexical_scope(&mut self, - mut ident: ast::Ident, + mut ident: Ident, ns: Namespace, record_used: Option) -> Option> { if ns == TypeNS { - ident = ast::Ident::with_empty_ctxt(ident.name); + ident = Ident::with_empty_ctxt(ident.name); } // Walk backwards up the ribs in scope. @@ -1547,11 +1572,15 @@ impl<'a> Resolver<'a> { /// Resolves a "module prefix". A module prefix is one or both of (a) `self::`; /// (b) some chain of `super::`. /// grammar: (SELF MOD_SEP ) ? (SUPER MOD_SEP) * - fn resolve_module_prefix(&mut self, module_path: &[Name], span: Option) + fn resolve_module_prefix(&mut self, module_path: &[Ident], span: Option) -> ResolveResult> { + if &*module_path[0].name.as_str() == "$crate" { + return Success(PrefixFound(self.resolve_crate_var(module_path[0].ctxt), 1)); + } + // Start at the current module if we see `self` or `super`, or at the // top of the crate otherwise. - let mut i = match &*module_path[0].as_str() { + let mut i = match &*module_path[0].name.as_str() { "self" => 1, "super" => 0, _ => return Success(NoPrefixFound), @@ -1561,7 +1590,7 @@ impl<'a> Resolver<'a> { self.module_map[&self.current_module.normal_ancestor_id.unwrap()]; // Now loop through all the `super`s we find. - while i < module_path.len() && "super" == module_path[i].as_str() { + while i < module_path.len() && "super" == module_path[i].name.as_str() { debug!("(resolving module prefix) resolving `super` at {}", module_to_string(&containing_module)); if let Some(parent) = containing_module.parent { @@ -1579,6 +1608,14 @@ impl<'a> Resolver<'a> { return Success(PrefixFound(containing_module, i)); } + fn resolve_crate_var(&mut self, mut crate_var_ctxt: SyntaxContext) -> Module<'a> { + while crate_var_ctxt.source().0 != SyntaxContext::empty() { + crate_var_ctxt = crate_var_ctxt.source().0; + } + let module = self.invocations[&crate_var_ctxt.source().1].module.get(); + if module.is_local() { self.graph_root } else { module } + } + // AST resolution // // We maintain a list of value ribs and type ribs. @@ -1619,7 +1656,7 @@ impl<'a> Resolver<'a> { /// Searches the current set of local scopes for labels. /// Stops after meeting a closure. - fn search_label(&self, mut ident: ast::Ident) -> Option { + fn search_label(&self, mut ident: Ident) -> Option { for rib in self.label_ribs.iter().rev() { match rib.kind { NormalRibKind => { @@ -1783,7 +1820,7 @@ impl<'a> Resolver<'a> { // plain insert (no renaming) let def_id = self.definitions.local_def_id(type_parameter.id); let def = Def::TyParam(def_id); - function_type_rib.bindings.insert(ast::Ident::with_empty_ctxt(name), def); + function_type_rib.bindings.insert(Ident::with_empty_ctxt(name), def); self.record_def(type_parameter.id, PathResolution::new(def)); } self.type_ribs.push(function_type_rib); @@ -2241,7 +2278,7 @@ impl<'a> Resolver<'a> { pat_id: NodeId, outer_pat_id: NodeId, pat_src: PatternSource, - bindings: &mut FnvHashMap) + bindings: &mut FnvHashMap) -> PathResolution { // Add the binding to the local ribs, if it // doesn't already exist in the bindings map. (We @@ -2337,12 +2374,24 @@ impl<'a> Resolver<'a> { self.record_def(pat_id, resolution); } + fn resolve_struct_path(&mut self, node_id: NodeId, path: &Path) { + // Resolution logic is equivalent for expressions and patterns, + // reuse `resolve_pattern_path` for both. + self.resolve_pattern_path(node_id, None, path, TypeNS, |def| { + match def { + Def::Struct(..) | Def::Union(..) | Def::Variant(..) | + Def::TyAlias(..) | Def::AssociatedTy(..) | Def::SelfTy(..) => true, + _ => false, + } + }, "struct, variant or union type"); + } + fn resolve_pattern(&mut self, pat: &Pat, pat_src: PatternSource, // Maps idents to the node ID for the // outermost pattern that binds them. - bindings: &mut FnvHashMap) { + bindings: &mut FnvHashMap) { // Visit all direct subpatterns of this pattern. let outer_pat_id = pat.id; pat.walk(&mut |pat| { @@ -2356,15 +2405,16 @@ impl<'a> Resolver<'a> { let always_binding = !pat_src.is_refutable() || opt_pat.is_some() || bmode != BindingMode::ByValue(Mutability::Immutable); match def { - Def::Struct(..) | Def::Variant(..) | - Def::Const(..) | Def::AssociatedConst(..) if !always_binding => { - // A constant, unit variant, etc pattern. + Def::StructCtor(_, CtorKind::Const) | + Def::VariantCtor(_, CtorKind::Const) | + Def::Const(..) if !always_binding => { + // A unit struct/variant or constant pattern. let name = ident.node.name; self.record_use(name, ValueNS, binding.unwrap(), ident.span); Some(PathResolution::new(def)) } - Def::Struct(..) | Def::Variant(..) | - Def::Const(..) | Def::AssociatedConst(..) | Def::Static(..) => { + Def::StructCtor(..) | Def::VariantCtor(..) | + Def::Const(..) | Def::Static(..) => { // A fresh binding that shadows something unacceptable. resolve_error( self, @@ -2381,7 +2431,7 @@ impl<'a> Resolver<'a> { } def => { span_bug!(ident.span, "unexpected definition for an \ - identifier in pattern {:?}", def); + identifier in pattern: {:?}", def); } } }).unwrap_or_else(|| { @@ -2394,30 +2444,26 @@ impl<'a> Resolver<'a> { PatKind::TupleStruct(ref path, ..) => { self.resolve_pattern_path(pat.id, None, path, ValueNS, |def| { match def { - Def::Struct(..) | Def::Variant(..) => true, + Def::StructCtor(_, CtorKind::Fn) | + Def::VariantCtor(_, CtorKind::Fn) => true, _ => false, } - }, "variant or struct"); + }, "tuple struct/variant"); } PatKind::Path(ref qself, ref path) => { self.resolve_pattern_path(pat.id, qself.as_ref(), path, ValueNS, |def| { match def { - Def::Struct(..) | Def::Variant(..) | + Def::StructCtor(_, CtorKind::Const) | + Def::VariantCtor(_, CtorKind::Const) | Def::Const(..) | Def::AssociatedConst(..) => true, _ => false, } - }, "variant, struct or constant"); + }, "unit struct/variant or constant"); } PatKind::Struct(ref path, ..) => { - self.resolve_pattern_path(pat.id, None, path, TypeNS, |def| { - match def { - Def::Struct(..) | Def::Union(..) | Def::Variant(..) | - Def::TyAlias(..) | Def::AssociatedTy(..) => true, - _ => false, - } - }, "variant, struct or type alias"); + self.resolve_struct_path(pat.id, path); } _ => {} @@ -2525,7 +2571,8 @@ impl<'a> Resolver<'a> { let unqualified_def = resolve_identifier_with_fallback(self, None); let qualified_binding = self.resolve_module_relative_path(span, segments, namespace); match (qualified_binding, unqualified_def) { - (Ok(binding), Some(ref ud)) if binding.def() == ud.def => { + (Ok(binding), Some(ref ud)) if binding.def() == ud.def && + segments[0].identifier.name.as_str() != "$crate" => { self.session .add_lint(lint::builtin::UNUSED_QUALIFICATIONS, id, @@ -2540,7 +2587,7 @@ impl<'a> Resolver<'a> { // Resolve a single identifier fn resolve_identifier(&mut self, - identifier: ast::Ident, + identifier: Ident, namespace: Namespace, record_used: Option) -> Option { @@ -2648,12 +2695,8 @@ impl<'a> Resolver<'a> { namespace: Namespace) -> Result<&'a NameBinding<'a>, bool /* true if an error was reported */> { - let module_path = segments.split_last() - .unwrap() - .1 - .iter() - .map(|ps| ps.identifier.name) - .collect::>(); + let module_path = + segments.split_last().unwrap().1.iter().map(|ps| ps.identifier).collect::>(); let containing_module; match self.resolve_module_path(&module_path, UseLexicalScope, Some(span)) { @@ -2682,7 +2725,7 @@ impl<'a> Resolver<'a> { bool /* true if an error was reported */> where T: Named, { - let module_path = segments.split_last().unwrap().1.iter().map(T::name).collect::>(); + let module_path = segments.split_last().unwrap().1.iter().map(T::ident).collect::>(); let root_module = self.graph_root; let containing_module; @@ -2701,7 +2744,7 @@ impl<'a> Resolver<'a> { } } - let name = segments.last().unwrap().name(); + let name = segments.last().unwrap().ident().name; let result = self.resolve_name_in_module(containing_module, name, namespace, false, Some(span)); result.success().ok_or(false) @@ -2759,10 +2802,9 @@ impl<'a> Resolver<'a> { // Look for a field with the same name in the current self_type. if let Some(resolution) = self.def_map.get(&node_id) { match resolution.base_def { - Def::Enum(did) | Def::TyAlias(did) | Def::Union(did) | - Def::Struct(did) | Def::Variant(did) if resolution.depth == 0 => { - if let Some(fields) = self.structs.get(&did) { - if fields.iter().any(|&field_name| name == field_name) { + Def::Struct(did) | Def::Union(did) if resolution.depth == 0 => { + if let Some(field_names) = self.field_names.get(&did) { + if field_names.iter().any(|&field_name| name == field_name) { return Field; } } @@ -2829,13 +2871,11 @@ impl<'a> Resolver<'a> { if let Some(path_res) = self.resolve_possibly_assoc_item(expr.id, maybe_qself.as_ref(), path, ValueNS) { // Check if struct variant - let is_struct_variant = if let Def::Variant(variant_id) = path_res.base_def { - self.structs.contains_key(&variant_id) - } else { - false + let is_struct_variant = match path_res.base_def { + Def::VariantCtor(_, CtorKind::Fictive) => true, + _ => false, }; if is_struct_variant { - let _ = self.structs.contains_key(&path_res.base_def.def_id()); let path_name = path_names_to_string(path, 0); let mut err = resolve_struct_error(self, @@ -2868,9 +2908,6 @@ impl<'a> Resolver<'a> { } } else { // Be helpful if the name refers to a struct - // (The pattern matching def_tys where the id is in self.structs - // matches on regular structs while excluding tuple- and enum-like - // structs, which wouldn't result in this error.) let path_name = path_names_to_string(path, 0); let type_res = self.with_no_errors(|this| { this.resolve_path(expr.id, path, 0, TypeNS) @@ -2949,9 +2986,8 @@ impl<'a> Resolver<'a> { msg = format!("did you mean {}?", msg); } else { // we display a help message if this is a module - let name_path = path.segments.iter() - .map(|seg| seg.identifier.name) - .collect::>(); + let name_path: Vec<_> = + path.segments.iter().map(|seg| seg.identifier).collect(); match self.resolve_module_path(&name_path[..], UseLexicalScope, @@ -2985,23 +3021,7 @@ impl<'a> Resolver<'a> { } ExprKind::Struct(ref path, ..) => { - // Resolve the path to the structure it goes to. We don't - // check to ensure that the path is actually a structure; that - // is checked later during typeck. - match self.resolve_path(expr.id, path, 0, TypeNS) { - Ok(definition) => self.record_def(expr.id, definition), - Err(true) => self.record_def(expr.id, err_path_resolution()), - Err(false) => { - debug!("(resolving expression) didn't find struct def",); - - resolve_error(self, - path.span, - ResolutionError::DoesNotNameAStruct( - &path_names_to_string(path, 0)) - ); - self.record_def(expr.id, err_path_resolution()); - } - } + self.resolve_struct_path(expr.id, path); visit::walk_expr(self, expr); } @@ -3204,7 +3224,7 @@ impl<'a> Resolver<'a> { if name == lookup_name && ns == namespace { if filter_fn(name_binding.def()) { // create the path - let ident = ast::Ident::with_empty_ctxt(name); + let ident = Ident::with_empty_ctxt(name); let params = PathParameters::none(); let segment = PathSegment { identifier: ident, @@ -3238,7 +3258,7 @@ impl<'a> Resolver<'a> { _ if module.parent.is_none() => path_segments.clone(), ModuleKind::Def(_, name) => { let mut paths = path_segments.clone(); - let ident = ast::Ident::with_empty_ctxt(name); + let ident = Ident::with_empty_ctxt(name); let params = PathParameters::none(); let segm = PathSegment { identifier: ident, @@ -3284,7 +3304,7 @@ impl<'a> Resolver<'a> { } }; - let segments: Vec<_> = path.segments.iter().map(|seg| seg.identifier.name).collect(); + let segments: Vec<_> = path.segments.iter().map(|seg| seg.identifier).collect(); let mut path_resolution = err_path_resolution(); let vis = match self.resolve_module_path(&segments, DontUseLexicalScope, Some(path.span)) { Success(module) => { @@ -3315,7 +3335,8 @@ impl<'a> Resolver<'a> { vis.is_accessible_from(module.normal_ancestor_id.unwrap(), self) } - fn report_errors(&self) { + fn report_errors(&mut self) { + self.report_shadowing_errors(); let mut reported_spans = FnvHashSet(); for &AmbiguityError { span, name, b1, b2 } in &self.ambiguity_errors { @@ -3343,6 +3364,24 @@ impl<'a> Resolver<'a> { } } + fn report_shadowing_errors(&mut self) { + for (name, scope) in replace(&mut self.lexical_macro_resolutions, Vec::new()) { + self.resolve_macro_name(scope, name); + } + + let mut reported_errors = FnvHashSet(); + for binding in replace(&mut self.disallowed_shadowing, Vec::new()) { + if self.resolve_macro_name(binding.parent, binding.name).is_some() && + reported_errors.insert((binding.name, binding.span)) { + let msg = format!("`{}` is already in scope", binding.name); + self.session.struct_span_err(binding.span, &msg) + .note("macro-expanded `macro_rules!`s may not shadow \ + existing macros (see RFC 1560)") + .emit(); + } + } + } + fn report_conflict(&self, parent: Module, name: Name, @@ -3421,26 +3460,24 @@ impl<'a> Resolver<'a> { } } -fn names_to_string(names: &[Name]) -> String { +fn names_to_string(names: &[Ident]) -> String { let mut first = true; let mut result = String::new(); - for name in names { + for ident in names { if first { first = false } else { result.push_str("::") } - result.push_str(&name.as_str()); + result.push_str(&ident.name.as_str()); } result } fn path_names_to_string(path: &Path, depth: usize) -> String { - let names: Vec = path.segments[..path.segments.len() - depth] - .iter() - .map(|seg| seg.identifier.name) - .collect(); - names_to_string(&names[..]) + let names: Vec<_> = + path.segments[..path.segments.len() - depth].iter().map(|seg| seg.identifier).collect(); + names_to_string(&names) } /// When an entity with a given name is not available in scope, we search for @@ -3503,16 +3540,16 @@ fn show_candidates(session: &mut DiagnosticBuilder, fn module_to_string(module: Module) -> String { let mut names = Vec::new(); - fn collect_mod(names: &mut Vec, module: Module) { + fn collect_mod(names: &mut Vec, module: Module) { if let ModuleKind::Def(_, name) = module.kind { if let Some(parent) = module.parent { - names.push(name); + names.push(Ident::with_empty_ctxt(name)); collect_mod(names, parent); } } else { // danger, shouldn't be ident? - names.push(token::intern("")); - collect_mod(names, module); + names.push(token::str_to_ident("")); + collect_mod(names, module.parent.unwrap()); } } collect_mod(&mut names, module); @@ -3520,7 +3557,7 @@ fn module_to_string(module: Module) -> String { if names.is_empty() { return "???".to_string(); } - names_to_string(&names.into_iter().rev().collect::>()) + names_to_string(&names.into_iter().rev().collect::>()) } fn err_path_resolution() -> PathResolution { diff --git a/src/librustc_resolve/macros.rs b/src/librustc_resolve/macros.rs index 3a9fb84519..e3078a42f6 100644 --- a/src/librustc_resolve/macros.rs +++ b/src/librustc_resolve/macros.rs @@ -8,36 +8,75 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -use Resolver; -use rustc::middle::cstore::LoadedMacro; -use rustc::util::nodemap::FnvHashMap; -use std::cell::RefCell; -use std::mem; +use {Module, Resolver}; +use build_reduced_graph::BuildReducedGraphVisitor; +use rustc::hir::def_id::{CRATE_DEF_INDEX, DefIndex}; +use rustc::hir::map::{self, DefCollector}; +use std::cell::Cell; use std::rc::Rc; -use syntax::ast::{self, Name}; +use syntax::ast; use syntax::errors::DiagnosticBuilder; -use syntax::ext::base::{self, MultiModifier, MultiDecorator, MultiItemModifier}; -use syntax::ext::base::{NormalTT, Resolver as SyntaxResolver, SyntaxExtension}; -use syntax::ext::expand::{Expansion, Invocation, InvocationKind}; +use syntax::ext::base::{self, Determinacy, MultiModifier, MultiDecorator}; +use syntax::ext::base::{NormalTT, SyntaxExtension}; +use syntax::ext::expand::Expansion; use syntax::ext::hygiene::Mark; use syntax::ext::tt::macro_rules; -use syntax::feature_gate::{self, emit_feature_err}; -use syntax::parse::token::{self, intern}; +use syntax::parse::token::intern; use syntax::util::lev_distance::find_best_match_for_name; -use syntax::visit::{self, Visitor}; use syntax_pos::Span; -#[derive(Clone, Default)] -pub struct ExpansionData { - module: Rc, +#[derive(Clone)] +pub struct InvocationData<'a> { + pub module: Cell>, + pub def_index: DefIndex, + // True if this expansion is in a `const_integer` position, for example `[u32; m!()]`. + // c.f. `DefCollector::visit_ast_const_integer`. + pub const_integer: bool, + // The scope in which the invocation path is resolved. + pub legacy_scope: Cell>, + // The smallest scope that includes this invocation's expansion, + // or `Empty` if this invocation has not been expanded yet. + pub expansion: Cell>, } -// FIXME(jseyfried): merge with `::ModuleS`. -#[derive(Default)] -struct ModuleData { - parent: Option>, - macros: RefCell>>, - macros_escape: bool, +impl<'a> InvocationData<'a> { + pub fn root(graph_root: Module<'a>) -> Self { + InvocationData { + module: Cell::new(graph_root), + def_index: CRATE_DEF_INDEX, + const_integer: false, + legacy_scope: Cell::new(LegacyScope::Empty), + expansion: Cell::new(LegacyScope::Empty), + } + } +} + +#[derive(Copy, Clone)] +pub enum LegacyScope<'a> { + Empty, + Invocation(&'a InvocationData<'a>), // The scope of the invocation, not including its expansion + Expansion(&'a InvocationData<'a>), // The scope of the invocation, including its expansion + Binding(&'a LegacyBinding<'a>), +} + +impl<'a> LegacyScope<'a> { + fn simplify_expansion(mut invoc: &'a InvocationData<'a>) -> Self { + while let LegacyScope::Invocation(_) = invoc.expansion.get() { + match invoc.legacy_scope.get() { + LegacyScope::Expansion(new_invoc) => invoc = new_invoc, + LegacyScope::Binding(_) => break, + scope @ _ => return scope, + } + } + LegacyScope::Expansion(invoc) + } +} + +pub struct LegacyBinding<'a> { + pub parent: LegacyScope<'a>, + pub name: ast::Name, + ext: Rc, + pub span: Span, } impl<'a> base::Resolver for Resolver<'a> { @@ -45,37 +84,59 @@ impl<'a> base::Resolver for Resolver<'a> { self.session.next_node_id() } + fn get_module_scope(&mut self, id: ast::NodeId) -> Mark { + let mark = Mark::fresh(); + let module = self.module_map[&id]; + self.invocations.insert(mark, self.arenas.alloc_invocation_data(InvocationData { + module: Cell::new(module), + def_index: module.def_id().unwrap().index, + const_integer: false, + legacy_scope: Cell::new(LegacyScope::Empty), + expansion: Cell::new(LegacyScope::Empty), + })); + mark + } + fn visit_expansion(&mut self, mark: Mark, expansion: &Expansion) { - expansion.visit_with(&mut ExpansionVisitor { - current_module: self.expansion_data[&mark.as_u32()].module.clone(), + let invocation = self.invocations[&mark]; + self.collect_def_ids(invocation, expansion); + + self.current_module = invocation.module.get(); + let mut visitor = BuildReducedGraphVisitor { resolver: self, - }); + legacy_scope: LegacyScope::Invocation(invocation), + expansion: mark, + }; + expansion.visit_with(&mut visitor); + invocation.expansion.set(visitor.legacy_scope); } - fn add_macro(&mut self, scope: Mark, mut def: ast::MacroDef) { + fn add_macro(&mut self, scope: Mark, mut def: ast::MacroDef, export: bool) { if &def.ident.name.as_str() == "macro_rules" { self.session.span_err(def.span, "user-defined macros may not be named `macro_rules`"); } - if def.use_locally { - let ext = macro_rules::compile(&self.session.parse_sess, &def); - self.add_ext(scope, def.ident, Rc::new(ext)); - } - if def.export { + + let invocation = self.invocations[&scope]; + let binding = self.arenas.alloc_legacy_binding(LegacyBinding { + parent: invocation.legacy_scope.get(), + name: def.ident.name, + ext: Rc::new(macro_rules::compile(&self.session.parse_sess, &def)), + span: def.span, + }); + invocation.legacy_scope.set(LegacyScope::Binding(binding)); + self.macro_names.insert(def.ident.name); + + if export { def.id = self.next_node_id(); self.exported_macros.push(def); } } - fn add_ext(&mut self, scope: Mark, ident: ast::Ident, ext: Rc) { + fn add_ext(&mut self, ident: ast::Ident, ext: Rc) { if let NormalTT(..) = *ext { self.macro_names.insert(ident.name); } - - let mut module = self.expansion_data[&scope.as_u32()].module.clone(); - while module.macros_escape { - module = module.parent.clone().unwrap(); - } - module.macros.borrow_mut().insert(ident.name, ext); + self.builtin_macros.insert(ident.name, ext); } fn add_expansions_at_stmt(&mut self, id: ast::NodeId, macros: Vec) { @@ -85,7 +146,7 @@ impl<'a> base::Resolver for Resolver<'a> { fn find_attr_invoc(&mut self, attrs: &mut Vec) -> Option { for i in 0..attrs.len() { let name = intern(&attrs[i].name()); - match self.expansion_data[&0].module.macros.borrow().get(&name) { + match self.builtin_macros.get(&name) { Some(ext) => match **ext { MultiModifier(..) | MultiDecorator(..) | SyntaxExtension::AttrProcMacro(..) => { return Some(attrs.remove(i)) @@ -98,45 +159,76 @@ impl<'a> base::Resolver for Resolver<'a> { None } - fn resolve_invoc(&mut self, scope: Mark, invoc: &Invocation) -> Option> { - let (name, span) = match invoc.kind { - InvocationKind::Bang { ref mac, .. } => { - let path = &mac.node.path; - if path.segments.len() > 1 || path.global || - !path.segments[0].parameters.is_empty() { - self.session.span_err(path.span, - "expected macro name without module separators"); - return None; - } - (path.segments[0].identifier.name, path.span) + fn resolve_macro(&mut self, scope: Mark, path: &ast::Path, force: bool) + -> Result, Determinacy> { + if path.segments.len() > 1 || path.global || !path.segments[0].parameters.is_empty() { + self.session.span_err(path.span, "expected macro name without module separators"); + return Err(Determinacy::Determined); + } + let name = path.segments[0].identifier.name; + + let invocation = self.invocations[&scope]; + if let LegacyScope::Expansion(parent) = invocation.legacy_scope.get() { + invocation.legacy_scope.set(LegacyScope::simplify_expansion(parent)); + } + self.resolve_macro_name(invocation.legacy_scope.get(), name).ok_or_else(|| { + if force { + let msg = format!("macro undefined: '{}!'", name); + let mut err = self.session.struct_span_err(path.span, &msg); + self.suggest_macro_name(&name.as_str(), &mut err); + err.emit(); + Determinacy::Determined + } else { + Determinacy::Undetermined } - InvocationKind::Attr { ref attr, .. } => (intern(&*attr.name()), attr.span), - }; + }) + } +} - let mut module = self.expansion_data[&scope.as_u32()].module.clone(); +impl<'a> Resolver<'a> { + pub fn resolve_macro_name(&mut self, mut scope: LegacyScope<'a>, name: ast::Name) + -> Option> { + let mut possible_time_travel = None; + let mut relative_depth: u32 = 0; loop { - if let Some(ext) = module.macros.borrow().get(&name) { - return Some(ext.clone()); - } - match module.parent.clone() { - Some(parent) => module = parent, - None => break, - } + scope = match scope { + LegacyScope::Empty => break, + LegacyScope::Expansion(invocation) => { + if let LegacyScope::Empty = invocation.expansion.get() { + if possible_time_travel.is_none() { + possible_time_travel = Some(scope); + } + invocation.legacy_scope.get() + } else { + relative_depth += 1; + invocation.expansion.get() + } + } + LegacyScope::Invocation(invocation) => { + relative_depth = relative_depth.saturating_sub(1); + invocation.legacy_scope.get() + } + LegacyScope::Binding(binding) => { + if binding.name == name { + if let Some(scope) = possible_time_travel { + // Check for disallowed shadowing later + self.lexical_macro_resolutions.push((name, scope)); + } else if relative_depth > 0 { + self.disallowed_shadowing.push(binding); + } + return Some(binding.ext.clone()); + } + binding.parent + } + }; } - let mut err = - self.session.struct_span_err(span, &format!("macro undefined: '{}!'", name)); - self.suggest_macro_name(&name.as_str(), &mut err); - err.emit(); - None - } - - fn resolve_derive_mode(&mut self, ident: ast::Ident) -> Option> { - self.derive_modes.get(&ident.name).cloned() + if let Some(scope) = possible_time_travel { + self.lexical_macro_resolutions.push((name, scope)); + } + self.builtin_macros.get(&name).cloned() } -} -impl<'a> Resolver<'a> { fn suggest_macro_name(&mut self, name: &str, err: &mut DiagnosticBuilder<'a>) { if let Some(suggestion) = find_best_match_for_name(self.macro_names.iter(), name, None) { if suggestion != name { @@ -147,116 +239,31 @@ impl<'a> Resolver<'a> { } } - fn insert_custom_derive(&mut self, name: &str, ext: Rc, sp: Span) { - if !self.session.features.borrow().rustc_macro { - let sess = &self.session.parse_sess; - let msg = "loading custom derive macro crates is experimentally supported"; - emit_feature_err(sess, "rustc_macro", sp, feature_gate::GateIssue::Language, msg); - } - if self.derive_modes.insert(token::intern(name), ext).is_some() { - self.session.span_err(sp, &format!("cannot shadow existing derive mode `{}`", name)); - } - } -} - -struct ExpansionVisitor<'b, 'a: 'b> { - resolver: &'b mut Resolver<'a>, - current_module: Rc, -} - -impl<'a, 'b> ExpansionVisitor<'a, 'b> { - fn visit_invoc(&mut self, id: ast::NodeId) { - self.resolver.expansion_data.insert(id.as_u32(), ExpansionData { - module: self.current_module.clone(), - }); - } - - // does this attribute list contain "macro_use"? - fn contains_macro_use(&mut self, attrs: &[ast::Attribute]) -> bool { - for attr in attrs { - if attr.check_name("macro_escape") { - let msg = "macro_escape is a deprecated synonym for macro_use"; - let mut err = self.resolver.session.struct_span_warn(attr.span, msg); - if let ast::AttrStyle::Inner = attr.node.style { - err.help("consider an outer attribute, #[macro_use] mod ...").emit(); - } else { - err.emit(); - } - } else if !attr.check_name("macro_use") { - continue; - } + fn collect_def_ids(&mut self, invocation: &'a InvocationData<'a>, expansion: &Expansion) { + let Resolver { ref mut invocations, arenas, graph_root, .. } = *self; + let InvocationData { def_index, const_integer, .. } = *invocation; - if !attr.is_word() { - self.resolver.session.span_err(attr.span, - "arguments to macro_use are not allowed here"); - } - return true; - } - - false - } -} - -macro_rules! method { - ($visit:ident: $ty:ty, $invoc:path, $walk:ident) => { - fn $visit(&mut self, node: &$ty) { - match node.node { - $invoc(..) => self.visit_invoc(node.id), - _ => visit::$walk(self, node), - } - } - } -} - -impl<'a, 'b> Visitor for ExpansionVisitor<'a, 'b> { - method!(visit_trait_item: ast::TraitItem, ast::TraitItemKind::Macro, walk_trait_item); - method!(visit_impl_item: ast::ImplItem, ast::ImplItemKind::Macro, walk_impl_item); - method!(visit_stmt: ast::Stmt, ast::StmtKind::Mac, walk_stmt); - method!(visit_expr: ast::Expr, ast::ExprKind::Mac, walk_expr); - method!(visit_pat: ast::Pat, ast::PatKind::Mac, walk_pat); - method!(visit_ty: ast::Ty, ast::TyKind::Mac, walk_ty); + let visit_macro_invoc = &mut |invoc: map::MacroInvocationData| { + invocations.entry(invoc.mark).or_insert_with(|| { + arenas.alloc_invocation_data(InvocationData { + def_index: invoc.def_index, + const_integer: invoc.const_integer, + module: Cell::new(graph_root), + expansion: Cell::new(LegacyScope::Empty), + legacy_scope: Cell::new(LegacyScope::Empty), + }) + }); + }; - fn visit_item(&mut self, item: &ast::Item) { - match item.node { - ast::ItemKind::Mac(..) if item.id == ast::DUMMY_NODE_ID => {} // Scope placeholder - ast::ItemKind::Mac(..) => self.visit_invoc(item.id), - ast::ItemKind::Mod(..) => { - let module_data = ModuleData { - parent: Some(self.current_module.clone()), - macros: RefCell::new(FnvHashMap()), - macros_escape: self.contains_macro_use(&item.attrs), - }; - let orig_module = mem::replace(&mut self.current_module, Rc::new(module_data)); - visit::walk_item(self, item); - self.current_module = orig_module; - } - ast::ItemKind::ExternCrate(..) => { - // We need to error on `#[macro_use] extern crate` when it isn't at the - // crate root, because `$crate` won't work properly. - // FIXME(jseyfried): This will be nicer once `ModuleData` is merged with `ModuleS`. - let is_crate_root = self.current_module.parent.as_ref().unwrap().parent.is_none(); - for def in self.resolver.crate_loader.load_macros(item, is_crate_root) { - match def { - LoadedMacro::Def(def) => self.resolver.add_macro(Mark::root(), def), - LoadedMacro::CustomDerive(name, ext) => { - self.resolver.insert_custom_derive(&name, ext, item.span); - } - } + let mut def_collector = DefCollector::new(&mut self.definitions); + def_collector.visit_macro_invoc = Some(visit_macro_invoc); + def_collector.with_parent(def_index, |def_collector| { + if const_integer { + if let Expansion::Expr(ref expr) = *expansion { + def_collector.visit_ast_const_integer(expr); } - visit::walk_item(self, item); } - _ => visit::walk_item(self, item), - } - } - - fn visit_block(&mut self, block: &ast::Block) { - let module_data = ModuleData { - parent: Some(self.current_module.clone()), - macros: RefCell::new(FnvHashMap()), - macros_escape: false, - }; - let orig_module = mem::replace(&mut self.current_module, Rc::new(module_data)); - visit::walk_block(self, block); - self.current_module = orig_module; + expansion.visit_with(def_collector) + }); } } diff --git a/src/librustc_resolve/resolve_imports.rs b/src/librustc_resolve/resolve_imports.rs index fe21e52959..2b3945bd0d 100644 --- a/src/librustc_resolve/resolve_imports.rs +++ b/src/librustc_resolve/resolve_imports.rs @@ -8,7 +8,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -use self::Determinacy::*; use self::ImportDirectiveSubclass::*; use Module; @@ -25,7 +24,8 @@ use rustc::ty; use rustc::lint::builtin::PRIVATE_IN_PUBLIC; use rustc::hir::def::*; -use syntax::ast::{NodeId, Name}; +use syntax::ast::{Ident, NodeId, Name}; +use syntax::ext::base::Determinacy::{self, Determined, Undetermined}; use syntax::util::lev_distance::find_best_match_for_name; use syntax_pos::Span; @@ -37,12 +37,6 @@ impl<'a> Resolver<'a> { } } -#[derive(Copy, Clone, Debug)] -pub enum Determinacy { - Determined, - Undetermined, -} - /// Contains data for specific types of import directives. #[derive(Clone, Debug)] pub enum ImportDirectiveSubclass<'a> { @@ -75,7 +69,7 @@ impl<'a> ImportDirectiveSubclass<'a> { pub struct ImportDirective<'a> { pub id: NodeId, parent: Module<'a>, - module_path: Vec, + module_path: Vec, imported_module: Cell>>, // the resolution of `module_path` subclass: ImportDirectiveSubclass<'a>, span: Span, @@ -258,7 +252,7 @@ impl<'a> Resolver<'a> { // Add an import directive to the current module. pub fn add_import_directive(&mut self, - module_path: Vec, + module_path: Vec, subclass: ImportDirectiveSubclass<'a>, span: Span, id: NodeId, @@ -684,9 +678,8 @@ impl<'a, 'b:'a> ImportResolver<'a, 'b> { }; match (value_result, type_result) { - // With `#![feature(item_like_imports)]`, all namespaces - // must be re-exported with extra visibility for an error to occur. - (Ok(value_binding), Ok(type_binding)) if self.new_import_semantics => { + // All namespaces must be re-exported with extra visibility for an error to occur. + (Ok(value_binding), Ok(type_binding)) => { let vis = directive.vis.get(); if !value_binding.pseudo_vis().is_at_least(vis, self) && !type_binding.pseudo_vis().is_at_least(vis, self) { @@ -799,7 +792,7 @@ impl<'a, 'b:'a> ImportResolver<'a, 'b> { (binding.is_import() || binding.is_extern_crate()) { let def = binding.def(); if def != Def::Err { - reexports.push(Export { name: name, def_id: def.def_id() }); + reexports.push(Export { name: name, def: def }); } } @@ -823,7 +816,7 @@ impl<'a, 'b:'a> ImportResolver<'a, 'b> { } } -fn import_path_to_string(names: &[Name], subclass: &ImportDirectiveSubclass) -> String { +fn import_path_to_string(names: &[Ident], subclass: &ImportDirectiveSubclass) -> String { if names.is_empty() { import_directive_subclass_to_string(subclass) } else { diff --git a/src/librustc_save_analysis/dump_visitor.rs b/src/librustc_save_analysis/dump_visitor.rs index 0869ad168b..db4788c3ce 100644 --- a/src/librustc_save_analysis/dump_visitor.rs +++ b/src/librustc_save_analysis/dump_visitor.rs @@ -153,7 +153,7 @@ impl<'l, 'tcx: 'l, 'll, D: Dump + 'll> DumpVisitor<'l, 'tcx, 'll, D> { // What could go wrong...? if spans.len() < path.segments.len() { if generated_code(path.span) { - return vec!(); + return vec![]; } error!("Mis-calculated spans for path '{}'. Found {} spans, expected {}. Found spans:", path_to_string(path), @@ -166,12 +166,13 @@ impl<'l, 'tcx: 'l, 'll, D: Dump + 'll> DumpVisitor<'l, 'tcx, 'll, D> { loc.file.name, loc.line); } - return vec!(); + error!(" master span: {:?}: `{}`", path.span, self.span.snippet(path.span)); + return vec![]; } - let mut result: Vec<(Span, String)> = vec!(); + let mut result: Vec<(Span, String)> = vec![]; - let mut segs = vec!(); + let mut segs = vec![]; for (i, (seg, span)) in path.segments.iter().zip(&spans).enumerate() { segs.push(seg.clone()); let sub_path = ast::Path { @@ -271,12 +272,10 @@ impl<'l, 'tcx: 'l, 'll, D: Dump + 'll> DumpVisitor<'l, 'tcx, 'll, D> { } } - // looks up anything, not just a type - fn lookup_type_ref(&self, ref_id: NodeId) -> Option { + fn lookup_def_id(&self, ref_id: NodeId) -> Option { self.tcx.expect_def_or_none(ref_id).and_then(|def| { match def { - Def::PrimTy(..) => None, - Def::SelfTy(..) => None, + Def::PrimTy(..) | Def::SelfTy(..) => None, def => Some(def.def_id()), } }) @@ -303,10 +302,10 @@ impl<'l, 'tcx: 'l, 'll, D: Dump + 'll> DumpVisitor<'l, 'tcx, 'll, D> { }.lower(self.tcx)); } Def::Struct(..) | + Def::Variant(..) | Def::Union(..) | Def::Enum(..) | Def::TyAlias(..) | - Def::AssociatedTy(..) | Def::Trait(_) => { self.dumper.type_ref(TypeRefData { span: sub_span.expect("No span found for type ref"), @@ -316,11 +315,9 @@ impl<'l, 'tcx: 'l, 'll, D: Dump + 'll> DumpVisitor<'l, 'tcx, 'll, D> { }.lower(self.tcx)); } Def::Static(..) | - Def::Const(_) | - Def::AssociatedConst(..) | - Def::Local(..) | - Def::Variant(..) | - Def::Upvar(..) => { + Def::Const(..) | + Def::StructCtor(..) | + Def::VariantCtor(..) => { self.dumper.variable_ref(VariableRefData { span: sub_span.expect("No span found for var ref"), ref_id: def_id, @@ -335,10 +332,14 @@ impl<'l, 'tcx: 'l, 'll, D: Dump + 'll> DumpVisitor<'l, 'tcx, 'll, D> { scope: scope }.lower(self.tcx)); } + Def::Local(..) | + Def::Upvar(..) | Def::SelfTy(..) | Def::Label(_) | Def::TyParam(..) | Def::Method(..) | + Def::AssociatedTy(..) | + Def::AssociatedConst(..) | Def::PrimTy(_) | Def::Err => { span_bug!(span, @@ -355,7 +356,7 @@ impl<'l, 'tcx: 'l, 'll, D: Dump + 'll> DumpVisitor<'l, 'tcx, 'll, D> { collector.visit_pat(&arg.pat); let span_utils = self.span.clone(); for &(id, ref p, ..) in &collector.collected_paths { - let typ = self.tcx.node_types().get(&id).unwrap().to_string(); + let typ = self.tcx.tables().node_types.get(&id).unwrap().to_string(); // get the span only for the name of the variable (I hope the path is only ever a // variable name, but who knows?) let sub_span = span_utils.span_for_last_ident(p.span); @@ -422,7 +423,7 @@ impl<'l, 'tcx: 'l, 'll, D: Dump + 'll> DumpVisitor<'l, 'tcx, 'll, D> { None => { if let Some(NodeItem(item)) = self.tcx.map.get_if_local(id) { if let hir::ItemImpl(_, _, _, _, ref ty, _) = item.node { - trait_id = self.lookup_type_ref(ty.id); + trait_id = self.lookup_def_id(ty.id); } } } @@ -805,7 +806,7 @@ impl<'l, 'tcx: 'l, 'll, D: Dump + 'll> DumpVisitor<'l, 'tcx, 'll, D> { }; let trait_ref = &trait_ref.trait_ref; - if let Some(id) = self.lookup_type_ref(trait_ref.ref_id) { + if let Some(id) = self.lookup_def_id(trait_ref.ref_id) { let sub_span = self.span.sub_span_for_type_name(trait_ref.path.span); if !self.span.filter_generated(sub_span, trait_ref.path.span) { self.dumper.type_ref(TypeRefData { @@ -854,9 +855,7 @@ impl<'l, 'tcx: 'l, 'll, D: Dump + 'll> DumpVisitor<'l, 'tcx, 'll, D> { let path_data = match path_data { Some(pd) => pd, None => { - span_bug!(path.span, - "Unexpected def kind while looking up path in `{}`", - self.span.snippet(path.span)) + return; } }; @@ -924,13 +923,19 @@ impl<'l, 'tcx: 'l, 'll, D: Dump + 'll> DumpVisitor<'l, 'tcx, 'll, D> { } } } - Def::Local(..) | - Def::Static(..) | + Def::Fn(..) | Def::Const(..) | + Def::Static(..) | + Def::StructCtor(..) | + Def::VariantCtor(..) | Def::AssociatedConst(..) | + Def::Local(..) | + Def::Upvar(..) | Def::Struct(..) | + Def::Union(..) | Def::Variant(..) | - Def::Fn(..) => self.write_sub_paths_truncated(path, false), + Def::TyAlias(..) | + Def::AssociatedTy(..) => self.write_sub_paths_truncated(path, false), _ => {} } } @@ -983,7 +988,7 @@ impl<'l, 'tcx: 'l, 'll, D: Dump + 'll> DumpVisitor<'l, 'tcx, 'll, D> { match p.node { PatKind::Struct(ref path, ref fields, _) => { visit::walk_path(self, path); - let adt = self.tcx.node_id_to_type(p.id).ty_adt_def().unwrap(); + let adt = self.tcx.tables().node_id_to_type(p.id).ty_adt_def().unwrap(); let variant = adt.variant_of_def(self.tcx.expect_def(p.id)); for &Spanned { node: ref field, span } in fields { @@ -1018,8 +1023,7 @@ impl<'l, 'tcx: 'l, 'll, D: Dump + 'll> DumpVisitor<'l, 'tcx, 'll, D> { ast::Mutability::Immutable => value.to_string(), _ => String::new(), }; - let types = self.tcx.node_types(); - let typ = match types.get(&id) { + let typ = match self.tcx.tables().node_types.get(&id) { Some(typ) => { let typ = typ.to_string(); if !value.is_empty() { @@ -1163,7 +1167,7 @@ impl<'l, 'tcx: 'l, 'll, D: Dump +'ll> Visitor for DumpVisitor<'l, 'tcx, 'll, D> match use_item.node { ast::ViewPathSimple(ident, ref path) => { let sub_span = self.span.span_for_last_ident(path.span); - let mod_id = match self.lookup_type_ref(item.id) { + let mod_id = match self.lookup_def_id(item.id) { Some(def_id) => { let scope = self.cur_scope; self.process_def_kind(item.id, path.span, sub_span, def_id, scope); @@ -1221,7 +1225,7 @@ impl<'l, 'tcx: 'l, 'll, D: Dump +'ll> Visitor for DumpVisitor<'l, 'tcx, 'll, D> for plid in list { let scope = self.cur_scope; let id = plid.node.id; - if let Some(def_id) = self.lookup_type_ref(id) { + if let Some(def_id) = self.lookup_def_id(id) { let span = plid.span; self.process_def_kind(id, span, Some(span), def_id, scope); } @@ -1316,7 +1320,7 @@ impl<'l, 'tcx: 'l, 'll, D: Dump +'ll> Visitor for DumpVisitor<'l, 'tcx, 'll, D> self.process_macro_use(t.span, t.id); match t.node { ast::TyKind::Path(_, ref path) => { - if let Some(id) = self.lookup_type_ref(t.id) { + if let Some(id) = self.lookup_def_id(t.id) { let sub_span = self.span.sub_span_for_type_name(t.span); if !self.span.filter_generated(sub_span, t.span) { self.dumper.type_ref(TypeRefData { @@ -1350,7 +1354,7 @@ impl<'l, 'tcx: 'l, 'll, D: Dump +'ll> Visitor for DumpVisitor<'l, 'tcx, 'll, D> } ast::ExprKind::Struct(ref path, ref fields, ref base) => { let hir_expr = self.save_ctxt.tcx.map.expect_expr(ex.id); - let adt = self.tcx.expr_ty(&hir_expr).ty_adt_def().unwrap(); + let adt = self.tcx.tables().expr_ty(&hir_expr).ty_adt_def().unwrap(); let def = self.tcx.expect_def(hir_expr.id); self.process_struct_lit(ex, path, fields, adt.variant_of_def(def), base) } @@ -1376,7 +1380,7 @@ impl<'l, 'tcx: 'l, 'll, D: Dump +'ll> Visitor for DumpVisitor<'l, 'tcx, 'll, D> return; } }; - let ty = &self.tcx.expr_ty_adjusted(&hir_node).sty; + let ty = &self.tcx.tables().expr_ty_adjusted(&hir_node).sty; match *ty { ty::TyAdt(def, _) => { let sub_span = self.span.sub_span_after_token(ex.span, token::Dot); @@ -1463,7 +1467,7 @@ impl<'l, 'tcx: 'l, 'll, D: Dump +'ll> Visitor for DumpVisitor<'l, 'tcx, 'll, D> } else { "".to_string() }; - let typ = self.tcx.node_types() + let typ = self.tcx.tables().node_types .get(&id).map(|t| t.to_string()).unwrap_or(String::new()); value.push_str(": "); value.push_str(&typ); @@ -1486,14 +1490,13 @@ impl<'l, 'tcx: 'l, 'll, D: Dump +'ll> Visitor for DumpVisitor<'l, 'tcx, 'll, D> }.lower(self.tcx)); } } - Def::Variant(..) | Def::Enum(..) | - Def::TyAlias(..) | Def::Struct(..) => { + Def::StructCtor(..) | Def::VariantCtor(..) | + Def::Const(..) | Def::AssociatedConst(..) | + Def::Struct(..) | Def::Variant(..) | + Def::TyAlias(..) | Def::AssociatedTy(..) | + Def::SelfTy(..) => { paths_to_process.push((id, p.clone(), Some(ref_kind))) } - // FIXME(nrc) what are these doing here? - Def::Static(..) | - Def::Const(..) | - Def::AssociatedConst(..) => {} def => error!("unexpected definition kind when processing collected paths: {:?}", def), } diff --git a/src/librustc_save_analysis/json_dumper.rs b/src/librustc_save_analysis/json_dumper.rs index 0378d75cc6..eb613c3afd 100644 --- a/src/librustc_save_analysis/json_dumper.rs +++ b/src/librustc_save_analysis/json_dumper.rs @@ -129,7 +129,7 @@ impl From for Id { #[derive(Debug, RustcEncodable)] struct Import { kind: ImportKind, - id: Id, + ref_id: Option, span: SpanData, name: String, value: String, @@ -146,7 +146,7 @@ impl From for Import { fn from(data: ExternCrateData) -> Import { Import { kind: ImportKind::ExternCrate, - id: From::from(data.id), + ref_id: None, span: data.span, name: data.name, value: String::new(), @@ -157,7 +157,7 @@ impl From for Import { fn from(data: UseData) -> Import { Import { kind: ImportKind::Use, - id: From::from(data.id), + ref_id: data.mod_id.map(|id| From::from(id)), span: data.span, name: data.name, value: String::new(), @@ -168,7 +168,7 @@ impl From for Import { fn from(data: UseGlobData) -> Import { Import { kind: ImportKind::GlobUse, - id: From::from(data.id), + ref_id: None, span: data.span, name: "*".to_owned(), value: data.names.join(", "), diff --git a/src/librustc_save_analysis/lib.rs b/src/librustc_save_analysis/lib.rs index aa68a87312..9103b90d7d 100644 --- a/src/librustc_save_analysis/lib.rs +++ b/src/librustc_save_analysis/lib.rs @@ -18,7 +18,7 @@ #![cfg_attr(not(stage0), deny(warnings))] #![feature(custom_attribute)] -#![feature(dotdot_in_tuple_patterns)] +#![cfg_attr(stage0, feature(dotdot_in_tuple_patterns))] #![allow(unused_attributes)] #![feature(rustc_private)] #![feature(staged_api)] @@ -286,7 +286,7 @@ impl<'l, 'tcx: 'l> SaveContext<'l, 'tcx> { scope: NodeId) -> Option { if let Some(ident) = field.ident { let qualname = format!("::{}::{}", self.tcx.node_path_str(scope), ident); - let typ = self.tcx.node_types().get(&field.id).unwrap().to_string(); + let typ = self.tcx.tables().node_types.get(&field.id).unwrap().to_string(); let sub_span = self.span_utils.sub_span_before_token(field.span, token::Colon); filter!(self.span_utils, sub_span, field.span, None); Some(VariableData { @@ -418,7 +418,7 @@ impl<'l, 'tcx: 'l> SaveContext<'l, 'tcx> { pub fn get_expr_data(&self, expr: &ast::Expr) -> Option { let hir_node = self.tcx.map.expect_expr(expr.id); - let ty = self.tcx.expr_ty_adjusted_opt(&hir_node); + let ty = self.tcx.tables().expr_ty_adjusted_opt(&hir_node); if ty.is_none() || ty.unwrap().sty == ty::TyError { return None; } @@ -432,7 +432,7 @@ impl<'l, 'tcx: 'l> SaveContext<'l, 'tcx> { return None; } }; - match self.tcx.expr_ty_adjusted(&hir_node).sty { + match self.tcx.tables().expr_ty_adjusted(&hir_node).sty { ty::TyAdt(def, _) if !def.is_enum() => { let f = def.struct_variant().field_named(ident.node.name); let sub_span = self.span_utils.span_for_last_ident(expr.span); @@ -451,7 +451,7 @@ impl<'l, 'tcx: 'l> SaveContext<'l, 'tcx> { } } ast::ExprKind::Struct(ref path, ..) => { - match self.tcx.expr_ty_adjusted(&hir_node).sty { + match self.tcx.tables().expr_ty_adjusted(&hir_node).sty { ty::TyAdt(def, _) if !def.is_enum() => { let sub_span = self.span_utils.span_for_last_ident(path.span); filter!(self.span_utils, sub_span, path.span, None); @@ -472,7 +472,7 @@ impl<'l, 'tcx: 'l> SaveContext<'l, 'tcx> { } ast::ExprKind::MethodCall(..) => { let method_call = ty::MethodCall::expr(expr.id); - let method_id = self.tcx.tables.borrow().method_map[&method_call].def_id; + let method_id = self.tcx.tables().method_map[&method_call].def_id; let (def_id, decl_id) = match self.tcx.impl_or_trait_item(method_id).container() { ty::ImplContainer(_) => (Some(method_id), None), ty::TraitContainer(_) => (None, Some(method_id)), @@ -507,7 +507,8 @@ impl<'l, 'tcx: 'l> SaveContext<'l, 'tcx> { Def::Static(..) | Def::Const(..) | Def::AssociatedConst(..) | - Def::Variant(..) => { + Def::StructCtor(..) | + Def::VariantCtor(..) => { Some(Data::VariableRefData(VariableRefData { name: self.span_utils.snippet(sub_span.unwrap()), span: sub_span.unwrap(), @@ -516,9 +517,11 @@ impl<'l, 'tcx: 'l> SaveContext<'l, 'tcx> { })) } Def::Struct(def_id) | + Def::Variant(def_id, ..) | Def::Union(def_id) | Def::Enum(def_id) | Def::TyAlias(def_id) | + Def::AssociatedTy(def_id) | Def::Trait(def_id) | Def::TyParam(def_id) => { Some(Data::TypeRefData(TypeRefData { @@ -572,7 +575,10 @@ impl<'l, 'tcx: 'l> SaveContext<'l, 'tcx> { qualname: String::new() // FIXME: generate the real qualname })) } - _ => None, + Def::PrimTy(..) | + Def::SelfTy(..) | + Def::Label(..) | + Def::Err => None, } } diff --git a/src/librustc_save_analysis/span_utils.rs b/src/librustc_save_analysis/span_utils.rs index 953c655491..031b9a6a5a 100644 --- a/src/librustc_save_analysis/span_utils.rs +++ b/src/librustc_save_analysis/span_utils.rs @@ -139,9 +139,9 @@ impl<'a> SpanUtils<'a> { let mut prev = toks.real_token(); let mut result = None; let mut bracket_count = 0; - let mut last_span = None; + let mut prev_span = None; while prev.tok != token::Eof { - last_span = None; + prev_span = None; let mut next = toks.real_token(); if (next.tok == token::OpenDelim(token::Paren) || next.tok == token::Lt) && @@ -166,12 +166,12 @@ impl<'a> SpanUtils<'a> { }; if prev.tok.is_ident() && bracket_count == 0 { - last_span = Some(prev.sp); + prev_span = Some(prev.sp); } prev = next; } - if result.is_none() && last_span.is_some() { - return self.make_sub_span(span, last_span); + if result.is_none() && prev_span.is_some() { + return self.make_sub_span(span, prev_span); } return self.make_sub_span(span, result); } @@ -225,7 +225,7 @@ impl<'a> SpanUtils<'a> { // Nesting = 0: all idents outside of brackets: [Foo] // Nesting = 1: idents within one level of brackets: [Bar, Bar] pub fn spans_with_brackets(&self, span: Span, nesting: isize, limit: isize) -> Vec { - let mut result: Vec = vec!(); + let mut result: Vec = vec![]; let mut toks = self.retokenise_span(span); // We keep track of how many brackets we're nested in @@ -236,7 +236,7 @@ impl<'a> SpanUtils<'a> { if ts.tok == token::Eof { if bracket_count != 0 { if generated_code(span) { - return vec!(); + return vec![]; } let loc = self.sess.codemap().lookup_char_pos(span.lo); span_bug!(span, diff --git a/src/librustc_trans/abi.rs b/src/librustc_trans/abi.rs index 683ad76952..0a5b013c79 100644 --- a/src/librustc_trans/abi.rs +++ b/src/librustc_trans/abi.rs @@ -8,7 +8,7 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -use llvm::{self, ValueRef}; +use llvm::{self, ValueRef, Integer, Pointer, Float, Double, Struct, Array, Vector}; use base; use build::AllocaFcx; use common::{type_is_fat_ptr, BlockAndBuilder, C_uint}; @@ -519,6 +519,7 @@ impl FnType { "powerpc64" => cabi_powerpc64::compute_abi_info(ccx, self), "s390x" => cabi_s390x::compute_abi_info(ccx, self), "asmjs" => cabi_asmjs::compute_abi_info(ccx, self), + "wasm32" => cabi_asmjs::compute_abi_info(ccx, self), a => ccx.sess().fatal(&format!("unrecognized arch \"{}\" in target specification", a)) } @@ -598,3 +599,73 @@ impl FnType { } } } + +pub fn align_up_to(off: usize, a: usize) -> usize { + return (off + a - 1) / a * a; +} + +fn align(off: usize, ty: Type, pointer: usize) -> usize { + let a = ty_align(ty, pointer); + return align_up_to(off, a); +} + +pub fn ty_align(ty: Type, pointer: usize) -> usize { + match ty.kind() { + Integer => ((ty.int_width() as usize) + 7) / 8, + Pointer => pointer, + Float => 4, + Double => 8, + Struct => { + if ty.is_packed() { + 1 + } else { + let str_tys = ty.field_types(); + str_tys.iter().fold(1, |a, t| cmp::max(a, ty_align(*t, pointer))) + } + } + Array => { + let elt = ty.element_type(); + ty_align(elt, pointer) + } + Vector => { + let len = ty.vector_length(); + let elt = ty.element_type(); + ty_align(elt, pointer) * len + } + _ => bug!("ty_align: unhandled type") + } +} + +pub fn ty_size(ty: Type, pointer: usize) -> usize { + match ty.kind() { + Integer => ((ty.int_width() as usize) + 7) / 8, + Pointer => pointer, + Float => 4, + Double => 8, + Struct => { + if ty.is_packed() { + let str_tys = ty.field_types(); + str_tys.iter().fold(0, |s, t| s + ty_size(*t, pointer)) + } else { + let str_tys = ty.field_types(); + let size = str_tys.iter().fold(0, |s, t| { + align(s, *t, pointer) + ty_size(*t, pointer) + }); + align(size, ty, pointer) + } + } + Array => { + let len = ty.array_length(); + let elt = ty.element_type(); + let eltsz = ty_size(elt, pointer); + len * eltsz + } + Vector => { + let len = ty.vector_length(); + let elt = ty.element_type(); + let eltsz = ty_size(elt, pointer); + len * eltsz + }, + _ => bug!("ty_size: unhandled type") + } +} diff --git a/src/librustc_trans/adt.rs b/src/librustc_trans/adt.rs index 19337ba021..0f987933df 100644 --- a/src/librustc_trans/adt.rs +++ b/src/librustc_trans/adt.rs @@ -48,7 +48,6 @@ use std; use llvm::{ValueRef, True, IntEQ, IntNE}; use rustc::ty::layout; use rustc::ty::{self, Ty, AdtKind}; -use syntax::attr; use build::*; use common::*; use debuginfo::DebugLoc; @@ -66,8 +65,6 @@ pub enum BranchKind { Single } -type Hint = attr::ReprAttr; - #[derive(Copy, Clone)] pub struct MaybeSizedValue { pub value: ValueRef, @@ -119,9 +116,6 @@ fn compute_fields<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>, t: Ty<'tcx>, } } -/// This represents the (GEP) indices to follow to get to the discriminant field -pub type DiscrField = Vec; - /// LLVM-level types are a little complicated. /// /// C-like enums need to be actual ints, not wrapped in a struct, @@ -632,7 +626,7 @@ fn struct_field_ptr<'blk, 'tcx>(bcx: &BlockAndBuilder<'blk, 'tcx>, let meta = val.meta; - let offset = st.offset_of_field(ix).bytes(); + let offset = st.offsets[ix].bytes(); let unaligned_offset = C_uint(bcx.ccx(), offset); // Get the alignment of the field @@ -695,9 +689,11 @@ pub fn trans_const<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, t: Ty<'tcx>, discr: D let lldiscr = C_integral(Type::from_integer(ccx, d), discr.0 as u64, true); let mut vals_with_discr = vec![lldiscr]; vals_with_discr.extend_from_slice(vals); - let aligned_size = l.size(dl).bytes(); - let contents = build_const_struct(ccx, &variant.offset_after_field[..], - &vals_with_discr[..], variant.packed, aligned_size); + let mut contents = build_const_struct(ccx, &variant, &vals_with_discr[..]); + let needed_padding = l.size(dl).bytes() - variant.stride().bytes(); + if needed_padding > 0 { + contents.push(padding(ccx, needed_padding)); + } C_struct(ccx, &contents[..], false) } layout::UntaggedUnion { ref variants, .. }=> { @@ -707,9 +703,7 @@ pub fn trans_const<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, t: Ty<'tcx>, discr: D } layout::Univariant { ref variant, .. } => { assert_eq!(discr, Disr(0)); - let aligned_size = l.size(dl).bytes(); - let contents = build_const_struct(ccx, &variant.offset_after_field[..], - vals, variant.packed, aligned_size); + let contents = build_const_struct(ccx, &variant, vals); C_struct(ccx, &contents[..], variant.packed) } layout::Vector { .. } => { @@ -725,12 +719,8 @@ pub fn trans_const<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, t: Ty<'tcx>, discr: D } } layout::StructWrappedNullablePointer { ref nonnull, nndiscr, .. } => { - let aligned_size = l.size(dl).bytes(); if discr.0 == nndiscr { - C_struct(ccx, &build_const_struct(ccx, - &nonnull.offset_after_field[..], - vals, nonnull.packed, aligned_size), - false) + C_struct(ccx, &build_const_struct(ccx, &nonnull, vals), false) } else { let fields = compute_fields(ccx, t, nndiscr as usize, false); let vals = fields.iter().map(|&ty| { @@ -738,12 +728,7 @@ pub fn trans_const<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, t: Ty<'tcx>, discr: D // field; see #8506. C_null(type_of::sizing_type_of(ccx, ty)) }).collect::>(); - C_struct(ccx, &build_const_struct(ccx, - &nonnull.offset_after_field[..], - &vals[..], - false, - aligned_size), - false) + C_struct(ccx, &build_const_struct(ccx, &nonnull, &vals[..]), false) } } _ => bug!("trans_const: cannot handle type {} repreented as {:#?}", t, l) @@ -759,12 +744,10 @@ pub fn trans_const<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, t: Ty<'tcx>, discr: D /// a two-element struct will locate it at offset 4, and accesses to it /// will read the wrong memory. fn build_const_struct<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, - offset_after_field: &[layout::Size], - vals: &[ValueRef], - packed: bool, - aligned_size: u64) + st: &layout::Struct, + vals: &[ValueRef]) -> Vec { - assert_eq!(vals.len(), offset_after_field.len()); + assert_eq!(vals.len(), st.offsets.len()); if vals.len() == 0 { return Vec::new(); @@ -773,23 +756,19 @@ fn build_const_struct<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, // offset of current value let mut offset = 0; let mut cfields = Vec::new(); - let target_offsets = offset_after_field.iter().map(|i| i.bytes()); - for (&val, target_offset) in vals.iter().zip(target_offsets) { - assert!(!is_undef(val)); - cfields.push(val); - offset += machine::llsize_of_alloc(ccx, val_ty(val)); - if !packed { - let val_align = machine::llalign_of_min(ccx, val_ty(val)); - offset = roundup(offset, val_align); - } - if offset != target_offset { + let offsets = st.offsets.iter().map(|i| i.bytes()); + for (&val, target_offset) in vals.iter().zip(offsets) { + if offset < target_offset { cfields.push(padding(ccx, target_offset - offset)); offset = target_offset; } + assert!(!is_undef(val)); + cfields.push(val); + offset += machine::llsize_of_alloc(ccx, val_ty(val)); } - if offset < aligned_size { - cfields.push(padding(ccx, aligned_size - offset)); + if offset < st.stride().bytes() { + cfields.push(padding(ccx, st.stride().bytes() - offset)); } cfields diff --git a/src/librustc_trans/asm.rs b/src/librustc_trans/asm.rs index 308118b1fb..8c704cc329 100644 --- a/src/librustc_trans/asm.rs +++ b/src/librustc_trans/asm.rs @@ -61,7 +61,7 @@ pub fn trans_inline_asm<'blk, 'tcx>(bcx: Block<'blk, 'tcx>, // Default per-arch clobbers // Basically what clang does let arch_clobbers = match &bcx.sess().target.target.arch[..] { - "x86" | "x86_64" => vec!("~{dirflag}", "~{fpsr}", "~{flags}"), + "x86" | "x86_64" => vec!["~{dirflag}", "~{fpsr}", "~{flags}"], _ => Vec::new() }; diff --git a/src/librustc_trans/assert_module_sources.rs b/src/librustc_trans/assert_module_sources.rs index 7fe6d2bbfe..264ed4cd12 100644 --- a/src/librustc_trans/assert_module_sources.rs +++ b/src/librustc_trans/assert_module_sources.rs @@ -134,7 +134,7 @@ impl<'a, 'tcx> AssertModuleSource<'a, 'tcx> { /// Scan for a `cfg="foo"` attribute and check whether we have a /// cfg flag called `foo`. fn check_config(&self, attr: &ast::Attribute) -> bool { - let config = &self.tcx.map.krate().config; + let config = &self.tcx.sess.parse_sess.config; let value = self.field(attr, CFG); debug!("check_config(config={:?}, value={:?})", config, value); if config.iter().any(|c| c.check_name(&value[..])) { diff --git a/src/librustc_trans/back/link.rs b/src/librustc_trans/back/link.rs index 5dab82dbc7..ad8e0c1ee5 100644 --- a/src/librustc_trans/back/link.rs +++ b/src/librustc_trans/back/link.rs @@ -130,7 +130,7 @@ pub fn build_link_meta(incremental_hashes_map: &IncrementalHashesMap, -> LinkMeta { let r = LinkMeta { crate_name: name.to_owned(), - crate_hash: Svh::new(incremental_hashes_map[&DepNode::Krate]), + crate_hash: Svh::new(incremental_hashes_map[&DepNode::Krate].to_smaller_hash()), }; info!("{:?}", r); return r; @@ -239,7 +239,7 @@ pub fn invalid_output_for_target(sess: &Session, match (sess.target.target.options.dynamic_linking, sess.target.target.options.executables, crate_type) { (false, _, config::CrateTypeCdylib) | - (false, _, config::CrateTypeRustcMacro) | + (false, _, config::CrateTypeProcMacro) | (false, _, config::CrateTypeDylib) => true, (_, false, config::CrateTypeExecutable) => true, _ => false @@ -263,7 +263,7 @@ pub fn filename_for_input(sess: &Session, outputs.out_directory.join(&format!("lib{}.rlib", libname)) } config::CrateTypeCdylib | - config::CrateTypeRustcMacro | + config::CrateTypeProcMacro | config::CrateTypeDylib => { let (prefix, suffix) = (&sess.target.target.options.dll_prefix, &sess.target.target.options.dll_suffix); @@ -295,7 +295,7 @@ pub fn each_linked_rlib(sess: &Session, let fmts = fmts.get(&config::CrateTypeExecutable) .or_else(|| fmts.get(&config::CrateTypeStaticlib)) .or_else(|| fmts.get(&config::CrateTypeCdylib)) - .or_else(|| fmts.get(&config::CrateTypeRustcMacro)); + .or_else(|| fmts.get(&config::CrateTypeProcMacro)); let fmts = fmts.unwrap_or_else(|| { bug!("could not find formats for rlibs") }); @@ -636,7 +636,7 @@ fn link_natively(sess: &Session, { let mut linker = trans.linker_info.to_linker(&mut cmd, &sess); link_args(&mut *linker, sess, crate_type, tmpdir, - objects, out_filename, outputs); + objects, out_filename, outputs, trans); } cmd.args(&sess.target.target.options.late_link_args); for obj in &sess.target.target.options.post_link_objects { @@ -711,7 +711,8 @@ fn link_args(cmd: &mut Linker, tmpdir: &Path, objects: &[PathBuf], out_filename: &Path, - outputs: &OutputFilenames) { + outputs: &OutputFilenames, + trans: &CrateTranslation) { // The default library location, we need this to find the runtime. // The location of crates will be determined as needed. @@ -726,6 +727,13 @@ fn link_args(cmd: &mut Linker, } cmd.output_filename(out_filename); + if crate_type == config::CrateTypeExecutable && + sess.target.target.options.is_like_windows { + if let Some(ref s) = trans.windows_subsystem { + cmd.subsystem(s); + } + } + // If we're building a dynamic library then some platforms need to make sure // that all symbols are exported correctly from the dynamic library. if crate_type != config::CrateTypeExecutable { @@ -736,7 +744,7 @@ fn link_args(cmd: &mut Linker, // executable. This metadata is in a separate object file from the main // object file, so we link that in here. if crate_type == config::CrateTypeDylib || - crate_type == config::CrateTypeRustcMacro { + crate_type == config::CrateTypeProcMacro { cmd.add_object(&outputs.with_extension("metadata.o")); } diff --git a/src/librustc_trans/back/linker.rs b/src/librustc_trans/back/linker.rs index dd14f98c92..860903d259 100644 --- a/src/librustc_trans/back/linker.rs +++ b/src/librustc_trans/back/linker.rs @@ -92,6 +92,7 @@ pub trait Linker { fn whole_archives(&mut self); fn no_whole_archives(&mut self); fn export_symbols(&mut self, tmpdir: &Path, crate_type: CrateType); + fn subsystem(&mut self, subsystem: &str); } pub struct GnuLinker<'a> { @@ -245,7 +246,7 @@ impl<'a> Linker for GnuLinker<'a> { // have far more public symbols than we actually want to export, so we // hide them all here. if crate_type == CrateType::CrateTypeDylib || - crate_type == CrateType::CrateTypeRustcMacro { + crate_type == CrateType::CrateTypeProcMacro { return } @@ -294,6 +295,10 @@ impl<'a> Linker for GnuLinker<'a> { self.cmd.arg(arg); } + + fn subsystem(&mut self, subsystem: &str) { + self.cmd.arg(&format!("-Wl,--subsystem,{}", subsystem)); + } } pub struct MsvcLinker<'a> { @@ -441,6 +446,30 @@ impl<'a> Linker for MsvcLinker<'a> { arg.push(path); self.cmd.arg(&arg); } + + fn subsystem(&mut self, subsystem: &str) { + // Note that previous passes of the compiler validated this subsystem, + // so we just blindly pass it to the linker. + self.cmd.arg(&format!("/SUBSYSTEM:{}", subsystem)); + + // Windows has two subsystems we're interested in right now, the console + // and windows subsystems. These both implicitly have different entry + // points (starting symbols). The console entry point starts with + // `mainCRTStartup` and the windows entry point starts with + // `WinMainCRTStartup`. These entry points, defined in system libraries, + // will then later probe for either `main` or `WinMain`, respectively to + // start the application. + // + // In Rust we just always generate a `main` function so we want control + // to always start there, so we force the entry point on the windows + // subsystem to be `mainCRTStartup` to get everything booted up + // correctly. + // + // For more information see RFC #1665 + if subsystem == "windows" { + self.cmd.arg("/ENTRY:mainCRTStartup"); + } + } } fn exported_symbols(scx: &SharedCrateContext, @@ -450,7 +479,7 @@ fn exported_symbols(scx: &SharedCrateContext, // See explanation in GnuLinker::export_symbols, for // why we don't ever need dylib symbols on non-MSVC. if crate_type == CrateType::CrateTypeDylib || - crate_type == CrateType::CrateTypeRustcMacro { + crate_type == CrateType::CrateTypeProcMacro { if !scx.sess().target.target.options.is_like_msvc { return vec![]; } diff --git a/src/librustc_trans/back/rpath.rs b/src/librustc_trans/back/rpath.rs index 4ed860bd40..8758cdcf9d 100644 --- a/src/librustc_trans/back/rpath.rs +++ b/src/librustc_trans/back/rpath.rs @@ -68,7 +68,7 @@ fn get_rpaths(config: &mut RPathConfig, libs: &[PathBuf]) -> Vec { let rel_rpaths = get_rpaths_relative_to_output(config, libs); // And a final backup rpath to the global library location. - let fallback_rpaths = vec!(get_install_prefix_rpath(config)); + let fallback_rpaths = vec![get_install_prefix_rpath(config)]; fn log_rpaths(desc: &str, rpaths: &[String]) { debug!("{} rpaths:", desc); diff --git a/src/librustc_trans/back/symbol_names.rs b/src/librustc_trans/back/symbol_names.rs index f0661e03bc..bf2a5d76c1 100644 --- a/src/librustc_trans/back/symbol_names.rs +++ b/src/librustc_trans/back/symbol_names.rs @@ -99,7 +99,8 @@ use common::SharedCrateContext; use monomorphize::Instance; -use util::sha2::{Digest, Sha256}; +use rustc_data_structures::fmt_wrap::FmtWrap; +use rustc_data_structures::blake2b::Blake2bHasher; use rustc::middle::weak_lang_items; use rustc::hir::def_id::LOCAL_CRATE; @@ -113,21 +114,6 @@ use rustc::util::common::record_time; use syntax::attr; use syntax::parse::token::{self, InternedString}; -use serialize::hex::ToHex; - -use std::hash::Hasher; - -struct Sha256Hasher<'a>(&'a mut Sha256); - -impl<'a> Hasher for Sha256Hasher<'a> { - fn write(&mut self, msg: &[u8]) { - self.0.input(msg) - } - - fn finish(&self) -> u64 { - bug!("Sha256Hasher::finish should not be called"); - } -} fn get_symbol_hash<'a, 'tcx>(scx: &SharedCrateContext<'a, 'tcx>, @@ -149,12 +135,9 @@ fn get_symbol_hash<'a, 'tcx>(scx: &SharedCrateContext<'a, 'tcx>, let tcx = scx.tcx(); - let mut hash_state = scx.symbol_hasher().borrow_mut(); - record_time(&tcx.sess.perf_stats.symbol_hash_time, || { - hash_state.reset(); - let hasher = Sha256Hasher(&mut hash_state); - let mut hasher = ty::util::TypeIdHasher::new(tcx, hasher); + let mut hasher = ty::util::TypeIdHasher::new(tcx, Blake2bHasher::new(8, &[])); + record_time(&tcx.sess.perf_stats.symbol_hash_time, || { // the main symbol name is not necessarily unique; hash in the // compiler's internal def-path, guaranteeing each symbol has a // truly unique path @@ -175,8 +158,9 @@ fn get_symbol_hash<'a, 'tcx>(scx: &SharedCrateContext<'a, 'tcx>, }); // 64 bits should be enough to avoid collisions. - let output = hash_state.result_bytes(); - format!("h{}", output[..8].to_hex()) + let mut hasher = hasher.into_inner(); + let hash_bytes = hasher.finalize(); + format!("h{:x}", FmtWrap(hash_bytes)) } impl<'a, 'tcx> Instance<'tcx> { diff --git a/src/librustc_trans/back/write.rs b/src/librustc_trans/back/write.rs index 04b814e2b9..9012914dee 100644 --- a/src/librustc_trans/back/write.rs +++ b/src/librustc_trans/back/write.rs @@ -665,7 +665,7 @@ pub fn run_passes(sess: &Session, // Figure out what we actually need to build. let mut modules_config = ModuleConfig::new(tm, sess.opts.cg.passes.clone()); - let mut metadata_config = ModuleConfig::new(tm, vec!()); + let mut metadata_config = ModuleConfig::new(tm, vec![]); modules_config.opt_level = Some(get_llvm_opt_level(sess.opts.optimize)); modules_config.opt_size = Some(get_llvm_opt_size(sess.opts.optimize)); diff --git a/src/librustc_trans/base.rs b/src/librustc_trans/base.rs index a2f2e9dd8d..bd15035b8a 100644 --- a/src/librustc_trans/base.rs +++ b/src/librustc_trans/base.rs @@ -35,6 +35,7 @@ use back::link; use back::linker::LinkerInfo; use llvm::{Linkage, ValueRef, Vector, get_param}; use llvm; +use rustc::hir::def::Def; use rustc::hir::def_id::DefId; use middle::lang_items::{LangItem, ExchangeMallocFnLangItem, StartFnLangItem}; use rustc::ty::subst::Substs; @@ -44,7 +45,6 @@ use rustc::ty::adjustment::CustomCoerceUnsized; use rustc::dep_graph::{DepNode, WorkProduct}; use rustc::hir::map as hir_map; use rustc::util::common::time; -use rustc::mir::mir_map::MirMap; use session::config::{self, NoDebugInfo}; use rustc_incremental::IncrementalHashesMap; use session::Session; @@ -79,7 +79,6 @@ use type_::Type; use type_of; use value::Value; use Disr; -use util::sha2::Sha256; use util::nodemap::{NodeSet, FnvHashMap, FnvHashSet}; use arena::TypedArena; @@ -183,6 +182,14 @@ pub fn get_dataptr(bcx: Block, fat_ptr: ValueRef) -> ValueRef { StructGEP(bcx, fat_ptr, abi::FAT_PTR_ADDR) } +pub fn get_meta_builder(b: &Builder, fat_ptr: ValueRef) -> ValueRef { + b.struct_gep(fat_ptr, abi::FAT_PTR_EXTRA) +} + +pub fn get_dataptr_builder(b: &Builder, fat_ptr: ValueRef) -> ValueRef { + b.struct_gep(fat_ptr, abi::FAT_PTR_ADDR) +} + fn require_alloc_fn<'blk, 'tcx>(bcx: Block<'blk, 'tcx>, info_ty: Ty<'tcx>, it: LangItem) -> DefId { match bcx.tcx().lang_items.require(it) { Ok(id) => id, @@ -206,7 +213,7 @@ pub fn malloc_raw_dyn<'blk, 'tcx>(bcx: Block<'blk, 'tcx>, // Allocate space: let def_id = require_alloc_fn(bcx, info_ty, ExchangeMallocFnLangItem); - let r = Callee::def(bcx.ccx(), def_id, Substs::empty(bcx.tcx())) + let r = Callee::def(bcx.ccx(), def_id, bcx.tcx().intern_substs(&[])) .call(bcx, debug_loc, &[size, align], None); Result::new(r.bcx, PointerCast(r.bcx, r.val, llty_ptr)) @@ -247,124 +254,6 @@ pub fn bin_op_to_fcmp_predicate(op: hir::BinOp_) -> llvm::RealPredicate { } } -pub fn compare_fat_ptrs<'blk, 'tcx>(bcx: Block<'blk, 'tcx>, - lhs_addr: ValueRef, - lhs_extra: ValueRef, - rhs_addr: ValueRef, - rhs_extra: ValueRef, - _t: Ty<'tcx>, - op: hir::BinOp_, - debug_loc: DebugLoc) - -> ValueRef { - match op { - hir::BiEq => { - let addr_eq = ICmp(bcx, llvm::IntEQ, lhs_addr, rhs_addr, debug_loc); - let extra_eq = ICmp(bcx, llvm::IntEQ, lhs_extra, rhs_extra, debug_loc); - And(bcx, addr_eq, extra_eq, debug_loc) - } - hir::BiNe => { - let addr_eq = ICmp(bcx, llvm::IntNE, lhs_addr, rhs_addr, debug_loc); - let extra_eq = ICmp(bcx, llvm::IntNE, lhs_extra, rhs_extra, debug_loc); - Or(bcx, addr_eq, extra_eq, debug_loc) - } - hir::BiLe | hir::BiLt | hir::BiGe | hir::BiGt => { - // a OP b ~ a.0 STRICT(OP) b.0 | (a.0 == b.0 && a.1 OP a.1) - let (op, strict_op) = match op { - hir::BiLt => (llvm::IntULT, llvm::IntULT), - hir::BiLe => (llvm::IntULE, llvm::IntULT), - hir::BiGt => (llvm::IntUGT, llvm::IntUGT), - hir::BiGe => (llvm::IntUGE, llvm::IntUGT), - _ => bug!(), - }; - - let addr_eq = ICmp(bcx, llvm::IntEQ, lhs_addr, rhs_addr, debug_loc); - let extra_op = ICmp(bcx, op, lhs_extra, rhs_extra, debug_loc); - let addr_eq_extra_op = And(bcx, addr_eq, extra_op, debug_loc); - - let addr_strict = ICmp(bcx, strict_op, lhs_addr, rhs_addr, debug_loc); - Or(bcx, addr_strict, addr_eq_extra_op, debug_loc) - } - _ => { - bug!("unexpected fat ptr binop"); - } - } -} - -pub fn compare_scalar_types<'blk, 'tcx>(bcx: Block<'blk, 'tcx>, - lhs: ValueRef, - rhs: ValueRef, - t: Ty<'tcx>, - op: hir::BinOp_, - debug_loc: DebugLoc) - -> ValueRef { - match t.sty { - ty::TyTuple(ref tys) if tys.is_empty() => { - // We don't need to do actual comparisons for nil. - // () == () holds but () < () does not. - match op { - hir::BiEq | hir::BiLe | hir::BiGe => return C_bool(bcx.ccx(), true), - hir::BiNe | hir::BiLt | hir::BiGt => return C_bool(bcx.ccx(), false), - // refinements would be nice - _ => bug!("compare_scalar_types: must be a comparison operator"), - } - } - ty::TyBool => { - // FIXME(#36856) -- using `from_immediate` forces these booleans into `i8`, - // which works around some LLVM bugs - ICmp(bcx, - bin_op_to_icmp_predicate(op, false), - from_immediate(bcx, lhs), - from_immediate(bcx, rhs), - debug_loc) - } - ty::TyFnDef(..) | ty::TyFnPtr(_) | ty::TyUint(_) | ty::TyChar => { - ICmp(bcx, - bin_op_to_icmp_predicate(op, false), - lhs, - rhs, - debug_loc) - } - ty::TyRawPtr(mt) if common::type_is_sized(bcx.tcx(), mt.ty) => { - ICmp(bcx, - bin_op_to_icmp_predicate(op, false), - lhs, - rhs, - debug_loc) - } - ty::TyRawPtr(_) => { - let lhs_addr = Load(bcx, GEPi(bcx, lhs, &[0, abi::FAT_PTR_ADDR])); - let lhs_extra = Load(bcx, GEPi(bcx, lhs, &[0, abi::FAT_PTR_EXTRA])); - - let rhs_addr = Load(bcx, GEPi(bcx, rhs, &[0, abi::FAT_PTR_ADDR])); - let rhs_extra = Load(bcx, GEPi(bcx, rhs, &[0, abi::FAT_PTR_EXTRA])); - compare_fat_ptrs(bcx, - lhs_addr, - lhs_extra, - rhs_addr, - rhs_extra, - t, - op, - debug_loc) - } - ty::TyInt(_) => { - ICmp(bcx, - bin_op_to_icmp_predicate(op, true), - lhs, - rhs, - debug_loc) - } - ty::TyFloat(_) => { - FCmp(bcx, - bin_op_to_fcmp_predicate(op), - lhs, - rhs, - debug_loc) - } - // Should never get here, because t is scalar. - _ => bug!("non-scalar type passed to compare_scalar_types"), - } -} - pub fn compare_simd_types<'blk, 'tcx>(bcx: Block<'blk, 'tcx>, lhs: ValueRef, rhs: ValueRef, @@ -515,7 +404,7 @@ pub fn custom_coerce_unsize_info<'scx, 'tcx>(scx: &SharedCrateContext<'scx, 'tcx -> CustomCoerceUnsized { let trait_ref = ty::Binder(ty::TraitRef { def_id: scx.tcx().lang_items.coerce_unsized_trait().unwrap(), - substs: Substs::new_trait(scx.tcx(), source_ty, &[target_ty]) + substs: scx.tcx().mk_substs_trait(source_ty, &[target_ty]) }); match fulfill_obligation(scx, DUMMY_SP, trait_ref) { @@ -632,6 +521,11 @@ pub fn need_invoke(bcx: Block) -> bool { } } +pub fn call_assume<'a, 'tcx>(b: &Builder<'a, 'tcx>, val: ValueRef) { + let assume_intrinsic = b.ccx.get_intrinsic("llvm.assume"); + b.call(assume_intrinsic, &[val], None); +} + /// Helper for loading values from memory. Does the necessary conversion if the in-memory type /// differs from the type used for SSA values. Also handles various special cases where the type /// gives us better information about what we are loading. @@ -685,12 +579,9 @@ pub fn store_ty<'blk, 'tcx>(cx: Block<'blk, 'tcx>, v: ValueRef, dst: ValueRef, t debug!("store_ty: {:?} : {:?} <- {:?}", Value(dst), t, Value(v)); if common::type_is_fat_ptr(cx.tcx(), t) { - Store(cx, - ExtractValue(cx, v, abi::FAT_PTR_ADDR), - get_dataptr(cx, dst)); - Store(cx, - ExtractValue(cx, v, abi::FAT_PTR_EXTRA), - get_meta(cx, dst)); + let lladdr = ExtractValue(cx, v, abi::FAT_PTR_ADDR); + let llextra = ExtractValue(cx, v, abi::FAT_PTR_EXTRA); + store_fat_ptr(cx, lladdr, llextra, dst, t); } else { Store(cx, from_immediate(cx, v), dst); } @@ -708,11 +599,36 @@ pub fn store_fat_ptr<'blk, 'tcx>(cx: Block<'blk, 'tcx>, pub fn load_fat_ptr<'blk, 'tcx>(cx: Block<'blk, 'tcx>, src: ValueRef, - _ty: Ty<'tcx>) - -> (ValueRef, ValueRef) { - // FIXME: emit metadata - (Load(cx, get_dataptr(cx, src)), - Load(cx, get_meta(cx, src))) + ty: Ty<'tcx>) + -> (ValueRef, ValueRef) +{ + if cx.unreachable.get() { + // FIXME: remove me + return (Load(cx, get_dataptr(cx, src)), + Load(cx, get_meta(cx, src))); + } + + load_fat_ptr_builder(&B(cx), src, ty) +} + +pub fn load_fat_ptr_builder<'a, 'tcx>( + b: &Builder<'a, 'tcx>, + src: ValueRef, + t: Ty<'tcx>) + -> (ValueRef, ValueRef) +{ + + let ptr = get_dataptr_builder(b, src); + let ptr = if t.is_region_ptr() || t.is_unique() { + b.load_nonnull(ptr) + } else { + b.load(ptr) + }; + + // FIXME: emit metadata on `meta`. + let meta = b.load(get_meta_builder(b, src)); + + (ptr, meta) } pub fn from_immediate(bcx: Block, val: ValueRef) -> ValueRef { @@ -931,7 +847,7 @@ impl<'blk, 'tcx> FunctionContext<'blk, 'tcx> { common::validate_substs(instance.substs); (instance.substs, Some(instance.def)) } - None => (Substs::empty(ccx.tcx()), None) + None => (ccx.tcx().intern_substs(&[]), None) }; let local_id = def_id.and_then(|id| ccx.tcx().map.as_local_node_id(id)); @@ -949,7 +865,7 @@ impl<'blk, 'tcx> FunctionContext<'blk, 'tcx> { false }; - let mir = def_id.and_then(|id| ccx.get_mir(id)); + let mir = def_id.map(|id| ccx.tcx().item_mir(id)); let debug_context = if let (false, Some((instance, sig, abi)), &Some(ref mir)) = (no_debug, definition, &mir) { @@ -1280,6 +1196,9 @@ pub fn maybe_create_entry_wrapper(ccx: &CrateContext) { } let llfn = declare::declare_cfn(ccx, "main", llfty); + // `main` should respect same config for frame pointer elimination as rest of code + attributes::set_frame_pointer_elimination(ccx, llfn); + let llbb = unsafe { llvm::LLVMAppendBasicBlockInContext(ccx.llcx(), llfn, "top\0".as_ptr() as *const _) }; @@ -1294,7 +1213,7 @@ pub fn maybe_create_entry_wrapper(ccx: &CrateContext) { Ok(id) => id, Err(s) => ccx.sess().fatal(&s) }; - let empty_substs = Substs::empty(ccx.tcx()); + let empty_substs = ccx.tcx().intern_substs(&[]); let start_fn = Callee::def(ccx, start_def_id, empty_substs).reify(ccx); let args = { let opaque_rust_main = @@ -1333,12 +1252,27 @@ fn write_metadata(cx: &SharedCrateContext, reachable_ids: &NodeSet) -> Vec { use flate; - let any_library = cx.sess() - .crate_types - .borrow() - .iter() - .any(|ty| *ty != config::CrateTypeExecutable); - if !any_library { + #[derive(PartialEq, Eq, PartialOrd, Ord)] + enum MetadataKind { + None, + Uncompressed, + Compressed + } + + let kind = cx.sess().crate_types.borrow().iter().map(|ty| { + match *ty { + config::CrateTypeExecutable | + config::CrateTypeStaticlib | + config::CrateTypeCdylib => MetadataKind::None, + + config::CrateTypeRlib => MetadataKind::Uncompressed, + + config::CrateTypeDylib | + config::CrateTypeProcMacro => MetadataKind::Compressed, + } + }).max().unwrap(); + + if kind == MetadataKind::None { return Vec::new(); } @@ -1346,8 +1280,12 @@ fn write_metadata(cx: &SharedCrateContext, let metadata = cstore.encode_metadata(cx.tcx(), cx.export_map(), cx.link_meta(), - reachable_ids, - cx.mir_map()); + reachable_ids); + if kind == MetadataKind::Uncompressed { + return metadata; + } + + assert!(kind == MetadataKind::Compressed); let mut compressed = cstore.metadata_encoding_version().to_vec(); compressed.extend_from_slice(&flate::deflate_bytes(&metadata)); @@ -1590,7 +1528,6 @@ pub fn filter_reachable_ids(tcx: TyCtxt, reachable: NodeSet) -> NodeSet { } pub fn trans_crate<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, - mir_map: &MirMap<'tcx>, analysis: ty::CrateAnalysis, incremental_hashes_map: &IncrementalHashesMap) -> CrateTranslation { @@ -1614,9 +1551,7 @@ pub fn trans_crate<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, let link_meta = link::build_link_meta(incremental_hashes_map, name); let shared_ccx = SharedCrateContext::new(tcx, - &mir_map, export_map, - Sha256::new(), link_meta.clone(), reachable, check_overflow); @@ -1679,7 +1614,8 @@ pub fn trans_crate<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, metadata: metadata, reachable: vec![], no_builtins: no_builtins, - linker_info: linker_info + linker_info: linker_info, + windows_subsystem: None, }; } @@ -1779,8 +1715,21 @@ pub fn trans_crate<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, // `reachable_symbols` list later on so it should be ok. for cnum in sess.cstore.crates() { let syms = sess.cstore.reachable_ids(cnum); - reachable_symbols.extend(syms.into_iter().filter(|did| { - sess.cstore.is_extern_item(shared_ccx.tcx(), *did) + reachable_symbols.extend(syms.into_iter().filter(|&def_id| { + let applicable = match sess.cstore.describe_def(def_id) { + Some(Def::Static(..)) => true, + Some(Def::Fn(_)) => { + shared_ccx.tcx().lookup_generics(def_id).types.is_empty() + } + _ => false + }; + + if applicable { + let attrs = shared_ccx.tcx().get_attrs(def_id); + attr::contains_extern_indicator(sess.diagnostic(), &attrs) + } else { + false + } }).map(|did| { symbol_for_def_id(did, &shared_ccx, &symbol_map) })); @@ -1802,6 +1751,17 @@ pub fn trans_crate<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, let linker_info = LinkerInfo::new(&shared_ccx, &reachable_symbols); + let subsystem = attr::first_attr_value_str_by_name(&krate.attrs, + "windows_subsystem"); + let windows_subsystem = subsystem.map(|subsystem| { + if subsystem != "windows" && subsystem != "console" { + tcx.sess.fatal(&format!("invalid windows subsystem `{}`, only \ + `windows` and `console` are allowed", + subsystem)); + } + subsystem.to_string() + }); + CrateTranslation { modules: modules, metadata_module: metadata_module, @@ -1809,7 +1769,8 @@ pub fn trans_crate<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, metadata: metadata, reachable: reachable_symbols, no_builtins: no_builtins, - linker_info: linker_info + linker_info: linker_info, + windows_subsystem: windows_subsystem, } } diff --git a/src/librustc_trans/cabi_aarch64.rs b/src/librustc_trans/cabi_aarch64.rs index fc11e3888d..59a8443995 100644 --- a/src/librustc_trans/cabi_aarch64.rs +++ b/src/librustc_trans/cabi_aarch64.rs @@ -11,78 +11,12 @@ #![allow(non_upper_case_globals)] use llvm::{Integer, Pointer, Float, Double, Struct, Array, Vector}; -use abi::{FnType, ArgType}; +use abi::{self, FnType, ArgType}; use context::CrateContext; use type_::Type; -use std::cmp; - -fn align_up_to(off: usize, a: usize) -> usize { - return (off + a - 1) / a * a; -} - -fn align(off: usize, ty: Type) -> usize { - let a = ty_align(ty); - return align_up_to(off, a); -} - -fn ty_align(ty: Type) -> usize { - match ty.kind() { - Integer => ((ty.int_width() as usize) + 7) / 8, - Pointer => 8, - Float => 4, - Double => 8, - Struct => { - if ty.is_packed() { - 1 - } else { - let str_tys = ty.field_types(); - str_tys.iter().fold(1, |a, t| cmp::max(a, ty_align(*t))) - } - } - Array => { - let elt = ty.element_type(); - ty_align(elt) - } - Vector => { - let len = ty.vector_length(); - let elt = ty.element_type(); - ty_align(elt) * len - } - _ => bug!("ty_align: unhandled type") - } -} - fn ty_size(ty: Type) -> usize { - match ty.kind() { - Integer => ((ty.int_width() as usize) + 7) / 8, - Pointer => 8, - Float => 4, - Double => 8, - Struct => { - if ty.is_packed() { - let str_tys = ty.field_types(); - str_tys.iter().fold(0, |s, t| s + ty_size(*t)) - } else { - let str_tys = ty.field_types(); - let size = str_tys.iter().fold(0, |s, t| align(s, *t) + ty_size(*t)); - align(size, ty) - } - } - Array => { - let len = ty.array_length(); - let elt = ty.element_type(); - let eltsz = ty_size(elt); - len * eltsz - } - Vector => { - let len = ty.vector_length(); - let elt = ty.element_type(); - let eltsz = ty_size(elt); - len * eltsz - } - _ => bug!("ty_size: unhandled type") - } + abi::ty_size(ty, 8) } fn is_homogenous_aggregate_ty(ty: Type) -> Option<(Type, u64)> { diff --git a/src/librustc_trans/cabi_arm.rs b/src/librustc_trans/cabi_arm.rs index 68a2e8aa8c..93d43f7d96 100644 --- a/src/librustc_trans/cabi_arm.rs +++ b/src/librustc_trans/cabi_arm.rs @@ -11,7 +11,7 @@ #![allow(non_upper_case_globals)] use llvm::{Integer, Pointer, Float, Double, Struct, Array, Vector}; -use abi::{FnType, ArgType}; +use abi::{self, align_up_to, FnType, ArgType}; use context::CrateContext; use type_::Type; @@ -24,40 +24,13 @@ pub enum Flavor { type TyAlignFn = fn(ty: Type) -> usize; -fn align_up_to(off: usize, a: usize) -> usize { - return (off + a - 1) / a * a; -} - fn align(off: usize, ty: Type, align_fn: TyAlignFn) -> usize { let a = align_fn(ty); return align_up_to(off, a); } fn general_ty_align(ty: Type) -> usize { - match ty.kind() { - Integer => ((ty.int_width() as usize) + 7) / 8, - Pointer => 4, - Float => 4, - Double => 8, - Struct => { - if ty.is_packed() { - 1 - } else { - let str_tys = ty.field_types(); - str_tys.iter().fold(1, |a, t| cmp::max(a, general_ty_align(*t))) - } - } - Array => { - let elt = ty.element_type(); - general_ty_align(elt) - } - Vector => { - let len = ty.vector_length(); - let elt = ty.element_type(); - general_ty_align(elt) * len - } - _ => bug!("ty_align: unhandled type") - } + abi::ty_align(ty, 4) } // For more information see: diff --git a/src/librustc_trans/cabi_mips.rs b/src/librustc_trans/cabi_mips.rs index 680310e195..25fe53e7ef 100644 --- a/src/librustc_trans/cabi_mips.rs +++ b/src/librustc_trans/cabi_mips.rs @@ -13,77 +13,17 @@ use libc::c_uint; use std::cmp; use llvm; -use llvm::{Integer, Pointer, Float, Double, Struct, Array, Vector}; -use abi::{ArgType, FnType}; +use llvm::{Integer, Pointer, Float, Double, Vector}; +use abi::{self, align_up_to, ArgType, FnType}; use context::CrateContext; use type_::Type; -fn align_up_to(off: usize, a: usize) -> usize { - return (off + a - 1) / a * a; -} - -fn align(off: usize, ty: Type) -> usize { - let a = ty_align(ty); - return align_up_to(off, a); -} - fn ty_align(ty: Type) -> usize { - match ty.kind() { - Integer => ((ty.int_width() as usize) + 7) / 8, - Pointer => 4, - Float => 4, - Double => 8, - Struct => { - if ty.is_packed() { - 1 - } else { - let str_tys = ty.field_types(); - str_tys.iter().fold(1, |a, t| cmp::max(a, ty_align(*t))) - } - } - Array => { - let elt = ty.element_type(); - ty_align(elt) - } - Vector => { - let len = ty.vector_length(); - let elt = ty.element_type(); - ty_align(elt) * len - } - _ => bug!("ty_align: unhandled type") - } + abi::ty_align(ty, 4) } fn ty_size(ty: Type) -> usize { - match ty.kind() { - Integer => ((ty.int_width() as usize) + 7) / 8, - Pointer => 4, - Float => 4, - Double => 8, - Struct => { - if ty.is_packed() { - let str_tys = ty.field_types(); - str_tys.iter().fold(0, |s, t| s + ty_size(*t)) - } else { - let str_tys = ty.field_types(); - let size = str_tys.iter().fold(0, |s, t| align(s, *t) + ty_size(*t)); - align(size, ty) - } - } - Array => { - let len = ty.array_length(); - let elt = ty.element_type(); - let eltsz = ty_size(elt); - len * eltsz - } - Vector => { - let len = ty.vector_length(); - let elt = ty.element_type(); - let eltsz = ty_size(elt); - len * eltsz - } - _ => bug!("ty_size: unhandled type") - } + abi::ty_size(ty, 4) } fn classify_ret_ty(ccx: &CrateContext, ret: &mut ArgType) { diff --git a/src/librustc_trans/cabi_mips64.rs b/src/librustc_trans/cabi_mips64.rs index e92ef1eaec..e6b500c88d 100644 --- a/src/librustc_trans/cabi_mips64.rs +++ b/src/librustc_trans/cabi_mips64.rs @@ -13,77 +13,17 @@ use libc::c_uint; use std::cmp; use llvm; -use llvm::{Integer, Pointer, Float, Double, Struct, Array, Vector}; -use abi::{ArgType, FnType}; +use llvm::{Integer, Pointer, Float, Double, Vector}; +use abi::{self, align_up_to, ArgType, FnType}; use context::CrateContext; use type_::Type; -fn align_up_to(off: usize, a: usize) -> usize { - return (off + a - 1) / a * a; -} - -fn align(off: usize, ty: Type) -> usize { - let a = ty_align(ty); - return align_up_to(off, a); -} - fn ty_align(ty: Type) -> usize { - match ty.kind() { - Integer => ((ty.int_width() as usize) + 7) / 8, - Pointer => 8, - Float => 4, - Double => 8, - Struct => { - if ty.is_packed() { - 1 - } else { - let str_tys = ty.field_types(); - str_tys.iter().fold(1, |a, t| cmp::max(a, ty_align(*t))) - } - } - Array => { - let elt = ty.element_type(); - ty_align(elt) - } - Vector => { - let len = ty.vector_length(); - let elt = ty.element_type(); - ty_align(elt) * len - } - _ => bug!("ty_align: unhandled type") - } + abi::ty_align(ty, 8) } fn ty_size(ty: Type) -> usize { - match ty.kind() { - Integer => ((ty.int_width() as usize) + 7) / 8, - Pointer => 8, - Float => 4, - Double => 8, - Struct => { - if ty.is_packed() { - let str_tys = ty.field_types(); - str_tys.iter().fold(0, |s, t| s + ty_size(*t)) - } else { - let str_tys = ty.field_types(); - let size = str_tys.iter().fold(0, |s, t| align(s, *t) + ty_size(*t)); - align(size, ty) - } - } - Array => { - let len = ty.array_length(); - let elt = ty.element_type(); - let eltsz = ty_size(elt); - len * eltsz - } - Vector => { - let len = ty.vector_length(); - let elt = ty.element_type(); - let eltsz = ty_size(elt); - len * eltsz - } - _ => bug!("ty_size: unhandled type") - } + abi::ty_size(ty, 8) } fn classify_ret_ty(ccx: &CrateContext, ret: &mut ArgType) { diff --git a/src/librustc_trans/cabi_powerpc.rs b/src/librustc_trans/cabi_powerpc.rs index e05c31b1d8..4e1d7a9337 100644 --- a/src/librustc_trans/cabi_powerpc.rs +++ b/src/librustc_trans/cabi_powerpc.rs @@ -10,67 +10,26 @@ use libc::c_uint; use llvm; -use llvm::{Integer, Pointer, Float, Double, Struct, Array}; -use abi::{FnType, ArgType}; +use llvm::{Integer, Pointer, Float, Double, Vector}; +use abi::{self, align_up_to, FnType, ArgType}; use context::CrateContext; use type_::Type; use std::cmp; -fn align_up_to(off: usize, a: usize) -> usize { - return (off + a - 1) / a * a; -} - -fn align(off: usize, ty: Type) -> usize { - let a = ty_align(ty); - return align_up_to(off, a); -} - fn ty_align(ty: Type) -> usize { - match ty.kind() { - Integer => ((ty.int_width() as usize) + 7) / 8, - Pointer => 4, - Float => 4, - Double => 8, - Struct => { - if ty.is_packed() { - 1 - } else { - let str_tys = ty.field_types(); - str_tys.iter().fold(1, |a, t| cmp::max(a, ty_align(*t))) - } - } - Array => { - let elt = ty.element_type(); - ty_align(elt) - } - _ => bug!("ty_size: unhandled type") + if ty.kind() == Vector { + bug!("ty_size: unhandled type") + } else { + abi::ty_align(ty, 4) } } fn ty_size(ty: Type) -> usize { - match ty.kind() { - Integer => ((ty.int_width() as usize) + 7) / 8, - Pointer => 4, - Float => 4, - Double => 8, - Struct => { - if ty.is_packed() { - let str_tys = ty.field_types(); - str_tys.iter().fold(0, |s, t| s + ty_size(*t)) - } else { - let str_tys = ty.field_types(); - let size = str_tys.iter().fold(0, |s, t| align(s, *t) + ty_size(*t)); - align(size, ty) - } - } - Array => { - let len = ty.array_length(); - let elt = ty.element_type(); - let eltsz = ty_size(elt); - len * eltsz - } - _ => bug!("ty_size: unhandled type") + if ty.kind() == Vector { + bug!("ty_size: unhandled type") + } else { + abi::ty_size(ty, 4) } } diff --git a/src/librustc_trans/cabi_powerpc64.rs b/src/librustc_trans/cabi_powerpc64.rs index ba54e369fd..cdc7c1fd1a 100644 --- a/src/librustc_trans/cabi_powerpc64.rs +++ b/src/librustc_trans/cabi_powerpc64.rs @@ -15,67 +15,16 @@ // Alignment of 128 bit types is not currently handled, this will // need to be fixed when PowerPC vector support is added. -use llvm::{Integer, Pointer, Float, Double, Struct, Array}; -use abi::{FnType, ArgType}; +use llvm::{Integer, Pointer, Float, Double, Struct, Vector, Array}; +use abi::{self, FnType, ArgType}; use context::CrateContext; use type_::Type; -use std::cmp; - -fn align_up_to(off: usize, a: usize) -> usize { - return (off + a - 1) / a * a; -} - -fn align(off: usize, ty: Type) -> usize { - let a = ty_align(ty); - return align_up_to(off, a); -} - -fn ty_align(ty: Type) -> usize { - match ty.kind() { - Integer => ((ty.int_width() as usize) + 7) / 8, - Pointer => 8, - Float => 4, - Double => 8, - Struct => { - if ty.is_packed() { - 1 - } else { - let str_tys = ty.field_types(); - str_tys.iter().fold(1, |a, t| cmp::max(a, ty_align(*t))) - } - } - Array => { - let elt = ty.element_type(); - ty_align(elt) - } - _ => bug!("ty_align: unhandled type") - } -} - fn ty_size(ty: Type) -> usize { - match ty.kind() { - Integer => ((ty.int_width() as usize) + 7) / 8, - Pointer => 8, - Float => 4, - Double => 8, - Struct => { - if ty.is_packed() { - let str_tys = ty.field_types(); - str_tys.iter().fold(0, |s, t| s + ty_size(*t)) - } else { - let str_tys = ty.field_types(); - let size = str_tys.iter().fold(0, |s, t| align(s, *t) + ty_size(*t)); - align(size, ty) - } - } - Array => { - let len = ty.array_length(); - let elt = ty.element_type(); - let eltsz = ty_size(elt); - len * eltsz - } - _ => bug!("ty_size: unhandled type") + if ty.kind() == Vector { + bug!("ty_size: unhandled type") + } else { + abi::ty_size(ty, 8) } } diff --git a/src/librustc_trans/cabi_s390x.rs b/src/librustc_trans/cabi_s390x.rs index 19404b667e..5a666c6083 100644 --- a/src/librustc_trans/cabi_s390x.rs +++ b/src/librustc_trans/cabi_s390x.rs @@ -12,16 +12,12 @@ // for a pre-z13 machine or using -mno-vx. use llvm::{Integer, Pointer, Float, Double, Struct, Array, Vector}; -use abi::{FnType, ArgType}; +use abi::{align_up_to, FnType, ArgType}; use context::CrateContext; use type_::Type; use std::cmp; -fn align_up_to(off: usize, a: usize) -> usize { - return (off + a - 1) / a * a; -} - fn align(off: usize, ty: Type) -> usize { let a = ty_align(ty); return align_up_to(off, a); diff --git a/src/librustc_trans/cabi_x86_64.rs b/src/librustc_trans/cabi_x86_64.rs index eb67f4ca61..33990148c8 100644 --- a/src/librustc_trans/cabi_x86_64.rs +++ b/src/librustc_trans/cabi_x86_64.rs @@ -16,12 +16,10 @@ use self::RegClass::*; use llvm::{Integer, Pointer, Float, Double}; use llvm::{Struct, Array, Attribute, Vector}; -use abi::{ArgType, FnType}; +use abi::{self, ArgType, FnType}; use context::CrateContext; use type_::Type; -use std::cmp; - #[derive(Clone, Copy, PartialEq)] enum RegClass { NoClass, @@ -90,62 +88,11 @@ fn classify_ty(ty: Type) -> Vec { } fn ty_align(ty: Type) -> usize { - match ty.kind() { - Integer => ((ty.int_width() as usize) + 7) / 8, - Pointer => 8, - Float => 4, - Double => 8, - Struct => { - if ty.is_packed() { - 1 - } else { - let str_tys = ty.field_types(); - str_tys.iter().fold(1, |a, t| cmp::max(a, ty_align(*t))) - } - } - Array => { - let elt = ty.element_type(); - ty_align(elt) - } - Vector => { - let len = ty.vector_length(); - let elt = ty.element_type(); - ty_align(elt) * len - } - _ => bug!("ty_align: unhandled type") - } + abi::ty_align(ty, 8) } fn ty_size(ty: Type) -> usize { - match ty.kind() { - Integer => (ty.int_width() as usize + 7) / 8, - Pointer => 8, - Float => 4, - Double => 8, - Struct => { - let str_tys = ty.field_types(); - if ty.is_packed() { - str_tys.iter().fold(0, |s, t| s + ty_size(*t)) - } else { - let size = str_tys.iter().fold(0, |s, t| align(s, *t) + ty_size(*t)); - align(size, ty) - } - } - Array => { - let len = ty.array_length(); - let elt = ty.element_type(); - let eltsz = ty_size(elt); - len * eltsz - } - Vector => { - let len = ty.vector_length(); - let elt = ty.element_type(); - let eltsz = ty_size(elt); - len * eltsz - } - - _ => bug!("ty_size: unhandled type") - } + abi::ty_size(ty, 8) } fn all_mem(cls: &mut [RegClass]) { diff --git a/src/librustc_trans/callee.rs b/src/librustc_trans/callee.rs index 05e22896c4..ffb13a833a 100644 --- a/src/librustc_trans/callee.rs +++ b/src/librustc_trans/callee.rs @@ -74,7 +74,7 @@ impl<'tcx> Callee<'tcx> { pub fn method_call<'blk>(bcx: Block<'blk, 'tcx>, method_call: ty::MethodCall) -> Callee<'tcx> { - let method = bcx.tcx().tables.borrow().method_map[&method_call]; + let method = bcx.tcx().tables().method_map[&method_call]; Callee::method(bcx, method) } @@ -302,9 +302,8 @@ fn trans_fn_pointer_shim<'a, 'tcx>( }; // Check if we already trans'd this shim. - match ccx.fn_pointer_shims().borrow().get(&bare_fn_ty_maybe_ref) { - Some(&llval) => { return llval; } - None => { } + if let Some(&llval) = ccx.fn_pointer_shims().borrow().get(&bare_fn_ty_maybe_ref) { + return llval; } debug!("trans_fn_pointer_shim(bare_fn_ty={:?})", @@ -327,7 +326,7 @@ fn trans_fn_pointer_shim<'a, 'tcx>( } }; let sig = tcx.erase_late_bound_regions_and_normalize(sig); - let tuple_input_ty = tcx.mk_tup(sig.inputs.to_vec()); + let tuple_input_ty = tcx.intern_tup(&sig.inputs[..]); let sig = ty::FnSig { inputs: vec![bare_fn_ty_maybe_ref, tuple_input_ty], diff --git a/src/librustc_trans/cleanup.rs b/src/librustc_trans/cleanup.rs index d368ce4743..b9f24eba9d 100644 --- a/src/librustc_trans/cleanup.rs +++ b/src/librustc_trans/cleanup.rs @@ -305,7 +305,7 @@ impl<'blk, 'tcx> FunctionContext<'blk, 'tcx> { assert!(orig_scopes_len > 0); // Remove any scopes that do not have cleanups on panic: - let mut popped_scopes = vec!(); + let mut popped_scopes = vec![]; while !self.top_scope(|s| s.needs_invoke()) { debug!("top scope does not need invoke"); popped_scopes.push(self.pop_scope()); @@ -402,7 +402,7 @@ impl<'blk, 'tcx> FunctionContext<'blk, 'tcx> { let orig_scopes_len = self.scopes_len(); let mut prev_llbb; - let mut popped_scopes = vec!(); + let mut popped_scopes = vec![]; let mut skip = 0; // First we pop off all the cleanup stacks that are @@ -585,8 +585,8 @@ impl<'tcx> CleanupScope<'tcx> { fn new(debug_loc: DebugLoc) -> CleanupScope<'tcx> { CleanupScope { debug_loc: debug_loc, - cleanups: vec!(), - cached_early_exits: vec!(), + cleanups: vec![], + cached_early_exits: vec![], cached_landing_pad: None, } } diff --git a/src/librustc_trans/collector.rs b/src/librustc_trans/collector.rs index 8112bb8e65..a439d415ed 100644 --- a/src/librustc_trans/collector.rs +++ b/src/librustc_trans/collector.rs @@ -198,15 +198,13 @@ use rustc::traits; use rustc::ty::subst::{Substs, Subst}; use rustc::ty::{self, TypeFoldable, TyCtxt}; use rustc::ty::adjustment::CustomCoerceUnsized; -use rustc::mir::repr as mir; +use rustc::mir::{self, Location}; use rustc::mir::visit as mir_visit; use rustc::mir::visit::Visitor as MirVisitor; -use rustc::mir::repr::Location; use rustc_const_eval as const_eval; use syntax::abi::Abi; -use errors; use syntax_pos::DUMMY_SP; use base::custom_coerce_unsize_info; use context::SharedCrateContext; @@ -347,8 +345,7 @@ fn collect_items_rec<'a, 'tcx: 'a>(scx: &SharedCrateContext<'a, 'tcx>, // Scan the MIR in order to find function calls, closures, and // drop-glue - let mir = errors::expect(scx.sess().diagnostic(), scx.get_mir(def_id), - || format!("Could not find MIR for static: {:?}", def_id)); + let mir = scx.tcx().item_mir(def_id); let empty_substs = scx.empty_substs_for_def_id(def_id); let visitor = MirNeighborCollector { @@ -368,8 +365,7 @@ fn collect_items_rec<'a, 'tcx: 'a>(scx: &SharedCrateContext<'a, 'tcx>, // Scan the MIR in order to find function calls, closures, and // drop-glue - let mir = errors::expect(scx.sess().diagnostic(), scx.get_mir(instance.def), - || format!("Could not find MIR for function: {}", instance)); + let mir = scx.tcx().item_mir(instance.def); let visitor = MirNeighborCollector { scx: scx, @@ -452,11 +448,7 @@ impl<'a, 'tcx> MirVisitor<'tcx> for MirNeighborCollector<'a, 'tcx> { match *rvalue { mir::Rvalue::Aggregate(mir::AggregateKind::Closure(def_id, ref substs), _) => { - let mir = errors::expect(self.scx.sess().diagnostic(), - self.scx.get_mir(def_id), - || { - format!("Could not find MIR for closure: {:?}", def_id) - }); + let mir = self.scx.tcx().item_mir(def_id); let concrete_substs = monomorphize::apply_param_substs(self.scx, self.param_substs, @@ -732,7 +724,7 @@ fn find_drop_glue_neighbors<'a, 'tcx>(scx: &SharedCrateContext<'a, 'tcx>, create_fn_trans_item(scx, exchange_free_fn_def_id, fn_substs, - Substs::empty(scx.tcx())); + scx.tcx().intern_substs(&[])); output.push(exchange_free_fn_trans_item); } @@ -752,7 +744,7 @@ fn find_drop_glue_neighbors<'a, 'tcx>(scx: &SharedCrateContext<'a, 'tcx>, .drop_trait() .unwrap(); - let self_type_substs = Substs::new_trait(scx.tcx(), ty, &[]); + let self_type_substs = scx.tcx().mk_substs_trait(ty, &[]); let trait_ref = ty::TraitRef { def_id: drop_trait_def_id, @@ -768,7 +760,7 @@ fn find_drop_glue_neighbors<'a, 'tcx>(scx: &SharedCrateContext<'a, 'tcx>, let trans_item = create_fn_trans_item(scx, destructor_did, substs, - Substs::empty(scx.tcx())); + scx.tcx().intern_substs(&[])); output.push(trans_item); } @@ -1035,7 +1027,7 @@ fn create_trans_items_for_vtable_methods<'a, 'tcx>(scx: &SharedCrateContext<'a, if let ty::TyTrait(ref trait_ty) = trait_ty.sty { let poly_trait_ref = trait_ty.principal.with_self_ty(scx.tcx(), impl_ty); - let param_substs = Substs::empty(scx.tcx()); + let param_substs = scx.tcx().intern_substs(&[]); // Walk all methods of the trait, including those of its supertraits let methods = traits::get_vtable_methods(scx.tcx(), poly_trait_ref); @@ -1090,10 +1082,7 @@ impl<'b, 'a, 'v> hir_visit::Visitor<'v> for RootCollector<'b, 'a, 'v> { hir::ItemStruct(_, ref generics) | hir::ItemUnion(_, ref generics) => { if !generics.is_parameterized() { - let ty = { - let tables = self.scx.tcx().tables.borrow(); - tables.node_types[&item.id] - }; + let ty = self.scx.tcx().tables().node_types[&item.id]; if self.mode == TransItemCollectionMode::Eager { debug!("RootCollector: ADT drop-glue for {}", @@ -1249,8 +1238,7 @@ fn collect_const_item_neighbours<'a, 'tcx>(scx: &SharedCrateContext<'a, 'tcx>, { // Scan the MIR in order to find function calls, closures, and // drop-glue - let mir = errors::expect(scx.sess().diagnostic(), scx.get_mir(def_id), - || format!("Could not find MIR for const: {:?}", def_id)); + let mir = scx.tcx().item_mir(def_id); let visitor = MirNeighborCollector { scx: scx, diff --git a/src/librustc_trans/common.rs b/src/librustc_trans/common.rs index 5b1f691af8..464b261b08 100644 --- a/src/librustc_trans/common.rs +++ b/src/librustc_trans/common.rs @@ -19,6 +19,7 @@ use llvm::{True, False, Bool, OperandBundleDef}; use rustc::hir::def::Def; use rustc::hir::def_id::DefId; use rustc::infer::TransNormalize; +use rustc::mir::Mir; use rustc::util::common::MemoizationMap; use middle::lang_items::LangItem; use rustc::ty::subst::Substs; @@ -32,7 +33,6 @@ use consts; use debuginfo::{self, DebugLoc}; use declare; use machine; -use mir::CachedMir; use monomorphize; use type_::Type; use value::Value; @@ -46,7 +46,7 @@ use arena::TypedArena; use libc::{c_uint, c_char}; use std::ops::Deref; use std::ffi::CString; -use std::cell::{Cell, RefCell}; +use std::cell::{Cell, RefCell, Ref}; use syntax::ast; use syntax::parse::token::InternedString; @@ -127,7 +127,7 @@ pub fn type_is_imm_pair<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, ty: Ty<'tcx>) Layout::FatPointer { .. } => true, Layout::Univariant { ref variant, .. } => { // There must be only 2 fields. - if variant.offset_after_field.len() != 2 { + if variant.offsets.len() != 2 { return false; } @@ -250,10 +250,8 @@ pub fn validate_substs(substs: &Substs) { // Function context. Every LLVM function we create will have one of // these. pub struct FunctionContext<'a, 'tcx: 'a> { - // The MIR for this function. At present, this is optional because - // we only have MIR available for things that are local to the - // crate. - pub mir: Option>, + // The MIR for this function. + pub mir: Option>>, // The ValueRef returned from a call to llvm::LLVMAddFunction; the // address of the first instruction in the sequence of @@ -313,8 +311,8 @@ pub struct FunctionContext<'a, 'tcx: 'a> { } impl<'a, 'tcx> FunctionContext<'a, 'tcx> { - pub fn mir(&self) -> CachedMir<'a, 'tcx> { - self.mir.clone().expect("fcx.mir was empty") + pub fn mir(&self) -> Ref<'tcx, Mir<'tcx>> { + self.mir.as_ref().map(Ref::clone).expect("fcx.mir was empty") } pub fn cleanup(&self) { @@ -376,7 +374,7 @@ impl<'a, 'tcx> FunctionContext<'a, 'tcx> { let tcx = ccx.tcx(); match tcx.lang_items.eh_personality() { Some(def_id) if !base::wants_msvc_seh(ccx.sess()) => { - Callee::def(ccx, def_id, Substs::empty(tcx)).reify(ccx) + Callee::def(ccx, def_id, tcx.intern_substs(&[])).reify(ccx) } _ => { if let Some(llpersonality) = ccx.eh_personality().get() { @@ -403,7 +401,7 @@ impl<'a, 'tcx> FunctionContext<'a, 'tcx> { let tcx = ccx.tcx(); assert!(ccx.sess().target.target.options.custom_unwind_resume); if let Some(def_id) = tcx.lang_items.eh_unwind_resume() { - return Callee::def(ccx, def_id, Substs::empty(tcx)); + return Callee::def(ccx, def_id, tcx.intern_substs(&[])); } let ty = tcx.mk_fn_ptr(tcx.mk_bare_fn(ty::BareFnTy { @@ -490,7 +488,7 @@ impl<'blk, 'tcx> BlockS<'blk, 'tcx> { self.set_lpad_ref(lpad.map(|p| &*self.fcx().lpad_arena.alloc(p))) } - pub fn mir(&self) -> CachedMir<'blk, 'tcx> { + pub fn mir(&self) -> Ref<'tcx, Mir<'tcx>> { self.fcx.mir() } @@ -609,7 +607,7 @@ impl<'blk, 'tcx> BlockAndBuilder<'blk, 'tcx> { self.bcx.llbb } - pub fn mir(&self) -> CachedMir<'blk, 'tcx> { + pub fn mir(&self) -> Ref<'tcx, Mir<'tcx>> { self.bcx.mir() } @@ -799,9 +797,7 @@ pub fn C_cstr(cx: &CrateContext, s: InternedString, null_terminated: bool) -> Va s.as_ptr() as *const c_char, s.len() as c_uint, !null_terminated as Bool); - - let gsym = token::gensym("str"); - let sym = format!("str{}", gsym.0); + let sym = cx.generate_local_symbol_name("str"); let g = declare::define_global(cx, &sym[..], val_ty(sc)).unwrap_or_else(||{ bug!("symbol `{}` is already defined", sym); }); diff --git a/src/librustc_trans/consts.rs b/src/librustc_trans/consts.rs index 15f7132e52..0dc10aa775 100644 --- a/src/librustc_trans/consts.rs +++ b/src/librustc_trans/consts.rs @@ -30,7 +30,6 @@ use rustc::hir; use std::ffi::{CStr, CString}; use syntax::ast; use syntax::attr; -use syntax::parse::token; pub fn ptrcast(val: ValueRef, ty: Type) -> ValueRef { unsafe { @@ -44,10 +43,7 @@ pub fn addr_of_mut(ccx: &CrateContext, kind: &str) -> ValueRef { unsafe { - // 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.0); + let name = ccx.generate_local_symbol_name(kind); let gv = declare::define_global(ccx, &name[..], val_ty(cv)).unwrap_or_else(||{ bug!("symbol `{}` is already defined", name); }); diff --git a/src/librustc_trans/context.rs b/src/librustc_trans/context.rs index 1b67516a9e..fc75b1018e 100644 --- a/src/librustc_trans/context.rs +++ b/src/librustc_trans/context.rs @@ -15,15 +15,12 @@ use middle::cstore::LinkMeta; use rustc::hir::def::ExportMap; use rustc::hir::def_id::DefId; use rustc::traits; -use rustc::mir::mir_map::MirMap; -use rustc::mir::repr as mir; use base; use builder::Builder; use common::BuilderRef_res; use debuginfo; use declare; use glue::DropGlueKind; -use mir::CachedMir; use monomorphize::Instance; use partitioning::CodegenUnit; @@ -35,7 +32,6 @@ use session::config::NoDebugInfo; use session::Session; use session::config; use symbol_map::SymbolMap; -use util::sha2::Sha256; use util::nodemap::{NodeSet, DefIdMap, FnvHashMap, FnvHashSet}; use std::ffi::{CStr, CString}; @@ -72,12 +68,9 @@ pub struct SharedCrateContext<'a, 'tcx: 'a> { export_map: ExportMap, reachable: NodeSet, link_meta: LinkMeta, - symbol_hasher: RefCell, tcx: TyCtxt<'a, 'tcx, 'tcx>, stats: Stats, check_overflow: bool, - mir_map: &'a MirMap<'tcx>, - mir_cache: RefCell>>, use_dll_storage_attrs: bool, @@ -166,6 +159,9 @@ pub struct LocalCrateContext<'tcx> { type_of_depth: Cell, symbol_map: Rc>, + + /// A counter that is used for generating local symbol names + local_gen_sym_counter: Cell, } // Implement DepTrackingMapConfig for `trait_cache` @@ -181,19 +177,6 @@ impl<'tcx> DepTrackingMapConfig for TraitSelectionCache<'tcx> { } } -// Cache for mir loaded from metadata -struct MirCache<'tcx> { - data: PhantomData<&'tcx ()> -} - -impl<'tcx> DepTrackingMapConfig for MirCache<'tcx> { - type Key = DefId; - type Value = Rc>; - fn to_dep_node(key: &DefId) -> DepNode { - DepNode::Mir(*key) - } -} - // # Global Cache pub struct ProjectionCache<'gcx> { @@ -450,9 +433,7 @@ unsafe fn create_context_and_module(sess: &Session, mod_name: &str) -> (ContextR impl<'b, 'tcx> SharedCrateContext<'b, 'tcx> { pub fn new(tcx: TyCtxt<'b, 'tcx, 'tcx>, - mir_map: &'b MirMap<'tcx>, export_map: ExportMap, - symbol_hasher: Sha256, link_meta: LinkMeta, reachable: NodeSet, check_overflow: bool) @@ -512,10 +493,7 @@ impl<'b, 'tcx> SharedCrateContext<'b, 'tcx> { export_map: export_map, reachable: reachable, link_meta: link_meta, - symbol_hasher: RefCell::new(symbol_hasher), tcx: tcx, - mir_map: mir_map, - mir_cache: RefCell::new(DepTrackingMap::new(tcx.dep_graph.clone())), stats: Stats { n_glues_created: Cell::new(0), n_null_glues: Cell::new(0), @@ -579,23 +557,6 @@ impl<'b, 'tcx> SharedCrateContext<'b, 'tcx> { self.use_dll_storage_attrs } - pub fn get_mir(&self, def_id: DefId) -> Option> { - if def_id.is_local() { - self.mir_map.map.get(&def_id).map(CachedMir::Ref) - } else { - if let Some(mir) = self.mir_cache.borrow().get(&def_id).cloned() { - return Some(CachedMir::Owned(mir)); - } - - let mir = self.sess().cstore.maybe_get_item_mir(self.tcx, def_id); - let cached = mir.map(Rc::new); - if let Some(ref mir) = cached { - self.mir_cache.borrow_mut().insert(def_id, mir.clone()); - } - cached.map(CachedMir::Owned) - } - } - pub fn translation_items(&self) -> &RefCell>> { &self.translation_items } @@ -610,14 +571,6 @@ impl<'b, 'tcx> SharedCrateContext<'b, 'tcx> { }) } - pub fn symbol_hasher(&self) -> &RefCell { - &self.symbol_hasher - } - - pub fn mir_map(&self) -> &MirMap<'tcx> { - &self.mir_map - } - pub fn metadata_symbol_name(&self) -> String { format!("rust_metadata_{}_{}", self.link_meta().crate_name, @@ -688,6 +641,7 @@ impl<'tcx> LocalCrateContext<'tcx> { n_llvm_insns: Cell::new(0), type_of_depth: Cell::new(0), symbol_map: symbol_map, + local_gen_sym_counter: Cell::new(0), }; let (int_type, opaque_vec_type, str_slice_ty, mut local_ccx) = { @@ -915,10 +869,6 @@ impl<'b, 'tcx> CrateContext<'b, 'tcx> { &self.local().llsizingtypes } - pub fn symbol_hasher<'a>(&'a self) -> &'a RefCell { - &self.shared.symbol_hasher - } - pub fn type_hashcodes<'a>(&'a self) -> &'a RefCell, String>> { &self.local().type_hashcodes } @@ -1004,10 +954,6 @@ impl<'b, 'tcx> CrateContext<'b, 'tcx> { self.shared.use_dll_storage_attrs() } - pub fn get_mir(&self, def_id: DefId) -> Option> { - self.shared.get_mir(def_id) - } - pub fn symbol_map(&self) -> &SymbolMap<'tcx> { &*self.local().symbol_map } @@ -1021,6 +967,16 @@ impl<'b, 'tcx> CrateContext<'b, 'tcx> { pub fn empty_substs_for_def_id(&self, item_def_id: DefId) -> &'tcx Substs<'tcx> { self.shared().empty_substs_for_def_id(item_def_id) } + + /// Generate a new symbol name with the given prefix. This symbol name must + /// only be used for definitions with `internal` or `private` linkage. + pub fn generate_local_symbol_name(&self, prefix: &str) -> String { + let idx = self.local().local_gen_sym_counter.get(); + self.local().local_gen_sym_counter.set(idx + 1); + // Include a '.' character, so there can be no accidental conflicts with + // user defined names + format!("{}.{}", prefix, idx) + } } pub struct TypeOfDepthLock<'a, 'tcx: 'a>(&'a LocalCrateContext<'tcx>); diff --git a/src/librustc_trans/debuginfo/create_scope_map.rs b/src/librustc_trans/debuginfo/create_scope_map.rs index 21716d55ac..e0c1a80be3 100644 --- a/src/librustc_trans/debuginfo/create_scope_map.rs +++ b/src/librustc_trans/debuginfo/create_scope_map.rs @@ -15,7 +15,7 @@ use super::utils::{DIB, span_start}; use llvm; use llvm::debuginfo::{DIScope, DISubprogram}; use common::{CrateContext, FunctionContext}; -use rustc::mir::repr::{Mir, VisibilityScope}; +use rustc::mir::{Mir, VisibilityScope}; use libc::c_uint; use std::ptr; @@ -45,7 +45,7 @@ impl MirDebugScope { /// Produce DIScope DIEs for each MIR Scope which has variables defined in it. /// If debuginfo is disabled, the returned vector is empty. pub fn create_mir_scopes(fcx: &FunctionContext) -> IndexVec { - let mir = fcx.mir.clone().expect("create_mir_scopes: missing MIR for fn"); + let mir = fcx.mir(); let null_scope = MirDebugScope { scope_metadata: ptr::null_mut(), file_start_pos: BytePos(0), @@ -63,8 +63,9 @@ pub fn create_mir_scopes(fcx: &FunctionContext) -> IndexVec TypeMap<'tcx> { // Get the string representation of a UniqueTypeId. This method will fail if // the id is unknown. - fn get_unique_type_id_as_string(&self, unique_type_id: UniqueTypeId) -> Rc { + fn get_unique_type_id_as_string(&self, unique_type_id: UniqueTypeId) -> Rc { let UniqueTypeId(interner_key) = unique_type_id; self.unique_id_interner.get(interner_key) } @@ -137,221 +143,33 @@ impl<'tcx> TypeMap<'tcx> { // ID will be generated and stored for later lookup. fn get_unique_type_id_of_type<'a>(&mut self, cx: &CrateContext<'a, 'tcx>, type_: Ty<'tcx>) -> UniqueTypeId { - - // basic type -> {:name of the type:} - // tuple -> {tuple_(:param-uid:)*} - // struct -> {struct_:svh: / :node-id:_<(:param-uid:),*> } - // enum -> {enum_:svh: / :node-id:_<(:param-uid:),*> } - // enum variant -> {variant_:variant-name:_:enum-uid:} - // reference (&) -> {& :pointee-uid:} - // mut reference (&mut) -> {&mut :pointee-uid:} - // ptr (*) -> {* :pointee-uid:} - // mut ptr (*mut) -> {*mut :pointee-uid:} - // unique ptr (box) -> {box :pointee-uid:} - // @-ptr (@) -> {@ :pointee-uid:} - // sized vec ([T; x]) -> {[:size:] :element-uid:} - // unsized vec ([T]) -> {[] :element-uid:} - // trait (T) -> {trait_:svh: / :node-id:_<(:param-uid:),*> } - // closure -> { :store-sigil: |(:param-uid:),* <,_...>| -> \ - // :return-type-uid: : (:bounds:)*} - // function -> { fn( (:param-uid:)* <,_...> ) -> \ - // :return-type-uid:} - + // Let's see if we already have something in the cache match self.type_to_unique_id.get(&type_).cloned() { Some(unique_type_id) => return unique_type_id, None => { /* generate one */} }; - let mut unique_type_id = String::with_capacity(256); - unique_type_id.push('{'); - - match type_.sty { - ty::TyNever | - ty::TyBool | - ty::TyChar | - ty::TyStr | - ty::TyInt(_) | - ty::TyUint(_) | - ty::TyFloat(_) => { - push_debuginfo_type_name(cx, type_, false, &mut unique_type_id); - }, - ty::TyAdt(def, substs) => { - unique_type_id.push_str(&(String::from(def.descr()) + " ")); - from_def_id_and_substs(self, cx, def.did, substs, &mut unique_type_id); - } - ty::TyTuple(component_types) if component_types.is_empty() => { - push_debuginfo_type_name(cx, type_, false, &mut unique_type_id); - }, - ty::TyTuple(component_types) => { - unique_type_id.push_str("tuple "); - for &component_type in component_types { - let component_type_id = - self.get_unique_type_id_of_type(cx, component_type); - let component_type_id = - self.get_unique_type_id_as_string(component_type_id); - unique_type_id.push_str(&component_type_id[..]); - } - }, - ty::TyBox(inner_type) => { - unique_type_id.push_str("box "); - let inner_type_id = self.get_unique_type_id_of_type(cx, inner_type); - let inner_type_id = self.get_unique_type_id_as_string(inner_type_id); - unique_type_id.push_str(&inner_type_id[..]); - }, - ty::TyRawPtr(ty::TypeAndMut { ty: inner_type, mutbl } ) => { - unique_type_id.push('*'); - if mutbl == hir::MutMutable { - unique_type_id.push_str("mut"); - } - - let inner_type_id = self.get_unique_type_id_of_type(cx, inner_type); - let inner_type_id = self.get_unique_type_id_as_string(inner_type_id); - unique_type_id.push_str(&inner_type_id[..]); - }, - ty::TyRef(_, ty::TypeAndMut { ty: inner_type, mutbl }) => { - unique_type_id.push('&'); - if mutbl == hir::MutMutable { - unique_type_id.push_str("mut"); - } - - let inner_type_id = self.get_unique_type_id_of_type(cx, inner_type); - let inner_type_id = self.get_unique_type_id_as_string(inner_type_id); - unique_type_id.push_str(&inner_type_id[..]); - }, - ty::TyArray(inner_type, len) => { - unique_type_id.push_str(&format!("[{}]", len)); - - let inner_type_id = self.get_unique_type_id_of_type(cx, inner_type); - let inner_type_id = self.get_unique_type_id_as_string(inner_type_id); - unique_type_id.push_str(&inner_type_id[..]); - }, - ty::TySlice(inner_type) => { - unique_type_id.push_str("[]"); - - let inner_type_id = self.get_unique_type_id_of_type(cx, inner_type); - let inner_type_id = self.get_unique_type_id_as_string(inner_type_id); - unique_type_id.push_str(&inner_type_id[..]); - }, - ty::TyTrait(ref trait_data) => { - unique_type_id.push_str("trait "); - - let principal = cx.tcx().erase_late_bound_regions_and_normalize( - &trait_data.principal); - - from_def_id_and_substs(self, - cx, - principal.def_id, - principal.substs, - &mut unique_type_id); - }, - ty::TyFnDef(.., &ty::BareFnTy{ unsafety, abi, ref sig } ) | - ty::TyFnPtr(&ty::BareFnTy{ unsafety, abi, ref sig } ) => { - if unsafety == hir::Unsafety::Unsafe { - unique_type_id.push_str("unsafe "); - } - - unique_type_id.push_str(abi.name()); - - unique_type_id.push_str(" fn("); - - let sig = cx.tcx().erase_late_bound_regions_and_normalize(sig); + // The hasher we are using to generate the UniqueTypeId. We want + // something that provides more than the 64 bits of the DefaultHasher. + const TYPE_ID_HASH_LENGTH: usize = 20; - for ¶meter_type in &sig.inputs { - let parameter_type_id = - self.get_unique_type_id_of_type(cx, parameter_type); - let parameter_type_id = - self.get_unique_type_id_as_string(parameter_type_id); - unique_type_id.push_str(¶meter_type_id[..]); - unique_type_id.push(','); - } + let mut type_id_hasher = TypeIdHasher::new(cx.tcx(), + Blake2bHasher::new(TYPE_ID_HASH_LENGTH, &[])); + type_id_hasher.visit_ty(type_); + let mut hash_state = type_id_hasher.into_inner(); + let hash: &[u8] = hash_state.finalize(); + debug_assert!(hash.len() == TYPE_ID_HASH_LENGTH); - if sig.variadic { - unique_type_id.push_str("..."); - } + let mut unique_type_id = String::with_capacity(TYPE_ID_HASH_LENGTH * 2); - unique_type_id.push_str(")->"); - let return_type_id = self.get_unique_type_id_of_type(cx, sig.output); - let return_type_id = self.get_unique_type_id_as_string(return_type_id); - unique_type_id.push_str(&return_type_id[..]); - }, - ty::TyClosure(_, substs) if substs.upvar_tys.is_empty() => { - push_debuginfo_type_name(cx, type_, false, &mut unique_type_id); - }, - ty::TyClosure(_, substs) => { - unique_type_id.push_str("closure "); - for upvar_type in substs.upvar_tys { - let upvar_type_id = - self.get_unique_type_id_of_type(cx, upvar_type); - let upvar_type_id = - self.get_unique_type_id_as_string(upvar_type_id); - unique_type_id.push_str(&upvar_type_id[..]); - } - }, - _ => { - bug!("get_unique_type_id_of_type() - unexpected type: {:?}", - type_) - } - }; - - unique_type_id.push('}'); - - // Trim to size before storing permanently - unique_type_id.shrink_to_fit(); + for byte in hash.into_iter() { + write!(&mut unique_type_id, "{:x}", byte).unwrap(); + } - let key = self.unique_id_interner.intern(unique_type_id); + let key = self.unique_id_interner.intern(&unique_type_id); self.type_to_unique_id.insert(type_, UniqueTypeId(key)); return UniqueTypeId(key); - - fn from_def_id_and_substs<'a, 'tcx>(type_map: &mut TypeMap<'tcx>, - cx: &CrateContext<'a, 'tcx>, - def_id: DefId, - substs: &Substs<'tcx>, - output: &mut String) { - // First, find out the 'real' def_id of the type. Items inlined from - // other crates have to be mapped back to their source. - let def_id = if let Some(node_id) = cx.tcx().map.as_local_node_id(def_id) { - if cx.tcx().map.is_inlined_node_id(node_id) { - // The given def_id identifies the inlined copy of a - // type definition, let's take the source of the copy. - cx.defid_for_inlined_node(node_id).unwrap() - } else { - def_id - } - } else { - def_id - }; - - // Get the crate name/disambiguator as first part of the identifier. - let crate_name = if def_id.is_local() { - cx.tcx().crate_name.clone() - } else { - cx.sess().cstore.original_crate_name(def_id.krate) - }; - let crate_disambiguator = cx.tcx().crate_disambiguator(def_id.krate); - - output.push_str(&crate_name[..]); - output.push_str("/"); - output.push_str(&crate_disambiguator[..]); - output.push_str("/"); - // Add the def-index as the second part - output.push_str(&format!("{:x}", def_id.index.as_usize())); - - if substs.types().next().is_some() { - output.push('<'); - - for type_parameter in substs.types() { - let param_type_id = - type_map.get_unique_type_id_of_type(cx, type_parameter); - let param_type_id = - type_map.get_unique_type_id_as_string(param_type_id); - output.push_str(¶m_type_id[..]); - output.push(','); - } - - output.push('>'); - } - } } // Get the UniqueTypeId for an enum variant. Enum variants are not really @@ -366,7 +184,7 @@ impl<'tcx> TypeMap<'tcx> { let enum_variant_type_id = format!("{}::{}", &self.get_unique_type_id_as_string(enum_type_id), variant_name); - let interner_key = self.unique_id_interner.intern(enum_variant_type_id); + let interner_key = self.unique_id_interner.intern(&enum_variant_type_id); UniqueTypeId(interner_key) } } @@ -1076,10 +894,6 @@ struct StructMemberDescriptionFactory<'tcx> { impl<'tcx> StructMemberDescriptionFactory<'tcx> { fn create_member_descriptions<'a>(&self, cx: &CrateContext<'a, 'tcx>) -> Vec { - if self.variant.kind == ty::VariantKind::Unit { - return Vec::new(); - } - let field_size = if self.is_simd { let fty = monomorphize::field_ty(cx.tcx(), self.substs, @@ -1093,7 +907,7 @@ impl<'tcx> StructMemberDescriptionFactory<'tcx> { }; self.variant.fields.iter().enumerate().map(|(i, f)| { - let name = if self.variant.kind == ty::VariantKind::Tuple { + let name = if self.variant.ctor_kind == CtorKind::Fn { format!("__{}", i) } else { f.name.to_string() @@ -1387,12 +1201,12 @@ impl<'tcx> EnumMemberDescriptionFactory<'tcx> { // For the metadata of the wrapper struct, we need to create a // MemberDescription of the struct's single field. let sole_struct_member_description = MemberDescription { - name: match non_null_variant.kind { - ty::VariantKind::Tuple => "__0".to_string(), - ty::VariantKind::Struct => { + name: match non_null_variant.ctor_kind { + CtorKind::Fn => "__0".to_string(), + CtorKind::Fictive => { non_null_variant.fields[0].name.to_string() } - ty::VariantKind::Unit => bug!() + CtorKind::Const => bug!() }, llvm_type: non_null_llvm_type, type_metadata: non_null_type_metadata, @@ -1579,16 +1393,16 @@ fn describe_enum_variant<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>, containing_scope); // Get the argument names from the enum variant info - let mut arg_names: Vec<_> = match variant.kind { - ty::VariantKind::Unit => vec![], - ty::VariantKind::Tuple => { + let mut arg_names: Vec<_> = match variant.ctor_kind { + CtorKind::Const => vec![], + CtorKind::Fn => { variant.fields .iter() .enumerate() .map(|(i, _)| format!("__{}", i)) .collect() } - ty::VariantKind::Struct => { + CtorKind::Fictive => { variant.fields .iter() .map(|f| f.name.to_string()) @@ -1930,15 +1744,17 @@ pub fn create_global_var_metadata(cx: &CrateContext, return; } + let tcx = cx.tcx(); + // Don't create debuginfo for globals inlined from other crates. The other // crate should already contain debuginfo for it. More importantly, the // global might not even exist in un-inlined form anywhere which would lead // to a linker errors. - if cx.tcx().map.is_inlined_node_id(node_id) { + if tcx.map.is_inlined_node_id(node_id) { return; } - let node_def_id = cx.tcx().map.local_def_id(node_id); + let node_def_id = tcx.map.local_def_id(node_id); let (var_scope, span) = get_namespace_and_span_for_item(cx, node_def_id); let (file_metadata, line_number) = if span != syntax_pos::DUMMY_SP { @@ -1949,9 +1765,9 @@ pub fn create_global_var_metadata(cx: &CrateContext, }; let is_local_to_unit = is_node_local_to_unit(cx, node_id); - let variable_type = cx.tcx().node_id_to_type(node_id); + let variable_type = tcx.erase_regions(&tcx.tables().node_id_to_type(node_id)); let type_metadata = type_metadata(cx, variable_type, span); - let var_name = cx.tcx().item_name(node_def_id).to_string(); + let var_name = tcx.item_name(node_def_id).to_string(); let linkage_name = mangled_name_of_item(cx, node_def_id, ""); let var_name = CString::new(var_name).unwrap(); diff --git a/src/librustc_trans/debuginfo/mod.rs b/src/librustc_trans/debuginfo/mod.rs index a23fd3ab8b..3bc5f4f3db 100644 --- a/src/librustc_trans/debuginfo/mod.rs +++ b/src/librustc_trans/debuginfo/mod.rs @@ -32,7 +32,7 @@ use abi::Abi; use common::{CrateContext, FunctionContext, Block, BlockAndBuilder}; use monomorphize::{self, Instance}; use rustc::ty::{self, Ty}; -use rustc::mir::repr as mir; +use rustc::mir; use session::config::{self, FullDebugInfo, LimitedDebugInfo, NoDebugInfo}; use util::nodemap::{DefIdMap, FnvHashMap, FnvHashSet}; @@ -482,8 +482,6 @@ pub fn declare_local<'blk, 'tcx>(bcx: Block<'blk, 'tcx>, type_metadata, cx.sess().opts.optimize != config::OptLevel::No, 0, - address_operations.as_ptr(), - address_operations.len() as c_uint, argument_index) }; source_loc::set_debug_location(cx, None, diff --git a/src/librustc_trans/glue.rs b/src/librustc_trans/glue.rs index fe76ec05f6..648dd9f3e3 100644 --- a/src/librustc_trans/glue.rs +++ b/src/librustc_trans/glue.rs @@ -48,7 +48,7 @@ pub fn trans_exchange_free_dyn<'blk, 'tcx>(bcx: Block<'blk, 'tcx>, let def_id = langcall(bcx.tcx(), None, "", ExchangeFreeFnLangItem); let args = [PointerCast(bcx, v, Type::i8p(bcx.ccx())), size, align]; - Callee::def(bcx.ccx(), def_id, Substs::empty(bcx.tcx())) + Callee::def(bcx.ccx(), def_id, bcx.tcx().intern_substs(&[])) .call(bcx, debug_loc, &args, None).bcx } @@ -292,7 +292,7 @@ fn trans_custom_dtor<'blk, 'tcx>(bcx: Block<'blk, 'tcx>, let trait_ref = ty::Binder(ty::TraitRef { def_id: tcx.lang_items.drop_trait().unwrap(), - substs: Substs::new_trait(tcx, t, &[]) + substs: tcx.mk_substs_trait(t, &[]) }); let vtbl = match fulfill_obligation(bcx.ccx().shared(), DUMMY_SP, trait_ref) { traits::VtableImpl(data) => data, @@ -335,20 +335,9 @@ pub fn size_and_align_of_dst<'blk, 'tcx>(bcx: &BlockAndBuilder<'blk, 'tcx>, let layout = ccx.layout_of(t); debug!("DST {} layout: {:?}", t, layout); - // Returns size in bytes of all fields except the last one - // (we will be recursing on the last one). - fn local_prefix_bytes(variant: &ty::layout::Struct) -> u64 { - let fields = variant.offset_after_field.len(); - if fields > 1 { - variant.offset_after_field[fields - 2].bytes() - } else { - 0 - } - } - let (sized_size, sized_align) = match *layout { ty::layout::Layout::Univariant { ref variant, .. } => { - (local_prefix_bytes(variant), variant.align.abi()) + (variant.offsets.last().map_or(0, |o| o.bytes()), variant.align.abi()) } _ => { bug!("size_and_align_of_dst: expcted Univariant for `{}`, found {:#?}", diff --git a/src/librustc_trans/lib.rs b/src/librustc_trans/lib.rs index 81c0c184f6..8ef7f04d4e 100644 --- a/src/librustc_trans/lib.rs +++ b/src/librustc_trans/lib.rs @@ -25,9 +25,10 @@ #![feature(box_patterns)] #![feature(box_syntax)] +#![feature(cell_extras)] #![feature(const_fn)] #![feature(custom_attribute)] -#![feature(dotdot_in_tuple_patterns)] +#![cfg_attr(stage0, feature(dotdot_in_tuple_patterns))] #![allow(unused_attributes)] #![feature(libc)] #![feature(quote)] @@ -168,6 +169,7 @@ pub struct CrateTranslation { pub metadata: Vec, pub reachable: Vec, pub no_builtins: bool, + pub windows_subsystem: Option, pub linker_info: back::linker::LinkerInfo } diff --git a/src/librustc_trans/meth.rs b/src/librustc_trans/meth.rs index dac70d4a1d..1e687f5ff6 100644 --- a/src/librustc_trans/meth.rs +++ b/src/librustc_trans/meth.rs @@ -119,9 +119,8 @@ pub fn get_vtable<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, debug!("get_vtable(trait_ref={:?})", trait_ref); // Check the cache. - match ccx.vtables().borrow().get(&trait_ref) { - Some(&val) => { return val } - None => { } + if let Some(&val) = ccx.vtables().borrow().get(&trait_ref) { + return val; } // Not in the cache. Build it. diff --git a/src/librustc_trans/mir/analyze.rs b/src/librustc_trans/mir/analyze.rs index 5de59b9f6b..e4d0533ec8 100644 --- a/src/librustc_trans/mir/analyze.rs +++ b/src/librustc_trans/mir/analyze.rs @@ -13,14 +13,11 @@ use rustc_data_structures::bitvec::BitVector; use rustc_data_structures::indexed_vec::{Idx, IndexVec}; -use rustc::mir::repr as mir; -use rustc::mir::repr::TerminatorKind; -use rustc::mir::repr::Location; +use rustc::mir::{self, Location, TerminatorKind}; use rustc::mir::visit::{Visitor, LvalueContext}; use rustc::mir::traversal; use common::{self, Block, BlockAndBuilder}; use glue; -use std::iter; use super::rvalue; pub fn lvalue_locals<'bcx, 'tcx>(bcx: Block<'bcx,'tcx>, @@ -30,11 +27,7 @@ pub fn lvalue_locals<'bcx, 'tcx>(bcx: Block<'bcx,'tcx>, analyzer.visit_mir(mir); - let local_types = mir.arg_decls.iter().map(|a| a.ty) - .chain(mir.var_decls.iter().map(|v| v.ty)) - .chain(mir.temp_decls.iter().map(|t| t.ty)) - .chain(iter::once(mir.return_ty)); - for (index, ty) in local_types.enumerate() { + for (index, ty) in mir.local_decls.iter().map(|l| l.ty).enumerate() { let ty = bcx.monomorphize(&ty); debug!("local {} has type {:?}", index, ty); if ty.is_scalar() || @@ -49,12 +42,6 @@ pub fn lvalue_locals<'bcx, 'tcx>(bcx: Block<'bcx,'tcx>, common::type_is_fat_ptr(bcx.tcx(), ty)); } else if common::type_is_imm_pair(bcx.ccx(), ty) { // We allow pairs and uses of any of their 2 fields. - } else if !analyzer.seen_assigned.contains(index) { - // No assignment has been seen, which means that - // either the local has been marked as lvalue - // already, or there is no possible initialization - // for the local, making any reads invalid. - // This is useful in weeding out dead temps. } else { // These sorts of types require an alloca. Note that // type_is_immediate() may *still* be true, particularly @@ -80,12 +67,11 @@ impl<'mir, 'bcx, 'tcx> LocalAnalyzer<'mir, 'bcx, 'tcx> { fn new(mir: &'mir mir::Mir<'tcx>, bcx: &'mir BlockAndBuilder<'bcx, 'tcx>) -> LocalAnalyzer<'mir, 'bcx, 'tcx> { - let local_count = mir.count_locals(); LocalAnalyzer { mir: mir, bcx: bcx, - lvalue_locals: BitVector::new(local_count), - seen_assigned: BitVector::new(local_count) + lvalue_locals: BitVector::new(mir.local_decls.len()), + seen_assigned: BitVector::new(mir.local_decls.len()) } } @@ -109,7 +95,7 @@ impl<'mir, 'bcx, 'tcx> Visitor<'tcx> for LocalAnalyzer<'mir, 'bcx, 'tcx> { location: Location) { debug!("visit_assign(block={:?}, lvalue={:?}, rvalue={:?})", block, lvalue, rvalue); - if let Some(index) = self.mir.local_index(lvalue) { + if let mir::Lvalue::Local(index) = *lvalue { self.mark_assigned(index); if !rvalue::rvalue_creates_operand(self.mir, self.bcx, rvalue) { self.mark_as_lvalue(index); @@ -153,7 +139,7 @@ impl<'mir, 'bcx, 'tcx> Visitor<'tcx> for LocalAnalyzer<'mir, 'bcx, 'tcx> { // Allow uses of projections of immediate pair fields. if let mir::Lvalue::Projection(ref proj) = *lvalue { - if self.mir.local_index(&proj.base).is_some() { + if let mir::Lvalue::Local(_) = proj.base { let ty = proj.base.ty(self.mir, self.bcx.tcx()); let ty = self.bcx.monomorphize(&ty.to_ty(self.bcx.tcx())); @@ -167,7 +153,7 @@ impl<'mir, 'bcx, 'tcx> Visitor<'tcx> for LocalAnalyzer<'mir, 'bcx, 'tcx> { } } - if let Some(index) = self.mir.local_index(lvalue) { + if let mir::Lvalue::Local(index) = *lvalue { match context { LvalueContext::Call => { self.mark_assigned(index); diff --git a/src/librustc_trans/mir/block.rs b/src/librustc_trans/mir/block.rs index 83b3880c38..8bf27b4bab 100644 --- a/src/librustc_trans/mir/block.rs +++ b/src/librustc_trans/mir/block.rs @@ -12,7 +12,7 @@ use llvm::{self, ValueRef}; use rustc_const_eval::{ErrKind, ConstEvalErr, note_const_eval_err}; use rustc::middle::lang_items; use rustc::ty; -use rustc::mir::repr as mir; +use rustc::mir; use abi::{Abi, FnType, ArgType}; use adt; use base; @@ -35,15 +35,16 @@ use syntax::parse::token; use super::{MirContext, LocalRef}; use super::analyze::CleanupKind; use super::constant::Const; -use super::lvalue::{LvalueRef, load_fat_ptr}; +use super::lvalue::{LvalueRef}; use super::operand::OperandRef; -use super::operand::OperandValue::*; +use super::operand::OperandValue::{Pair, Ref, Immediate}; + +use std::cell::Ref as CellRef; impl<'bcx, 'tcx> MirContext<'bcx, 'tcx> { pub fn trans_block(&mut self, bb: mir::BasicBlock) { let mut bcx = self.bcx(bb); - let mir = self.mir.clone(); - let data = &mir[bb]; + let data = &CellRef::clone(&self.mir)[bb]; debug!("trans_block({:?}={:?})", bb, data); @@ -192,8 +193,7 @@ impl<'bcx, 'tcx> MirContext<'bcx, 'tcx> { } let llval = if let Some(cast_ty) = ret.cast { - let index = mir.local_index(&mir::Lvalue::ReturnPointer).unwrap(); - let op = match self.locals[index] { + let op = match self.locals[mir::RETURN_POINTER] { LocalRef::Operand(Some(op)) => op, LocalRef::Operand(None) => bug!("use of return before def"), LocalRef::Lvalue(tr_lvalue) => { @@ -218,7 +218,7 @@ impl<'bcx, 'tcx> MirContext<'bcx, 'tcx> { } load } else { - let op = self.trans_consume(&bcx, &mir::Lvalue::ReturnPointer); + let op = self.trans_consume(&bcx, &mir::Lvalue::Local(mir::RETURN_POINTER)); op.pack_if_pair(&bcx).immediate() }; bcx.ret(llval); @@ -229,7 +229,7 @@ impl<'bcx, 'tcx> MirContext<'bcx, 'tcx> { } mir::TerminatorKind::Drop { ref location, target, unwind } => { - let ty = location.ty(&mir, bcx.tcx()).to_ty(bcx.tcx()); + let ty = location.ty(&self.mir, bcx.tcx()).to_ty(bcx.tcx()); let ty = bcx.monomorphize(&ty); // Double check for necessity to drop @@ -704,7 +704,7 @@ impl<'bcx, 'tcx> MirContext<'bcx, 'tcx> { for (n, &ty) in arg_types.iter().enumerate() { let ptr = adt::trans_field_ptr_builder(bcx, tuple.ty, base, Disr(0), n); let val = if common::type_is_fat_ptr(bcx.tcx(), ty) { - let (lldata, llextra) = load_fat_ptr(bcx, ptr); + let (lldata, llextra) = base::load_fat_ptr_builder(bcx, ptr, ty); Pair(lldata, llextra) } else { // trans_argument will load this if it needs to @@ -844,7 +844,7 @@ impl<'bcx, 'tcx> MirContext<'bcx, 'tcx> { if fn_ret_ty.is_ignore() { return ReturnDest::Nothing; } - let dest = if let Some(index) = self.mir.local_index(dest) { + let dest = if let mir::Lvalue::Local(index) = *dest { let ret_ty = self.monomorphized_lvalue_ty(dest); match self.locals[index] { LocalRef::Lvalue(dest) => dest, diff --git a/src/librustc_trans/mir/constant.rs b/src/librustc_trans/mir/constant.rs index b74d56ce36..3d0d889760 100644 --- a/src/librustc_trans/mir/constant.rs +++ b/src/librustc_trans/mir/constant.rs @@ -16,7 +16,7 @@ use rustc_const_math::ConstFloat::*; use rustc_const_math::{ConstInt, ConstIsize, ConstUsize, ConstMathErr}; use rustc::hir::def_id::DefId; use rustc::infer::TransNormalize; -use rustc::mir::repr as mir; +use rustc::mir; use rustc::mir::tcx::LvalueTy; use rustc::traits; use rustc::ty::{self, Ty, TyCtxt, TypeFoldable}; @@ -221,16 +221,17 @@ impl<'a, 'tcx> MirConstContext<'a, 'tcx> { fn new(ccx: &'a CrateContext<'a, 'tcx>, mir: &'a mir::Mir<'tcx>, substs: &'tcx Substs<'tcx>, - args: IndexVec>) + args: IndexVec>) -> MirConstContext<'a, 'tcx> { let mut context = MirConstContext { ccx: ccx, mir: mir, substs: substs, - locals: (0..mir.count_locals()).map(|_| None).collect(), + locals: (0..mir.local_decls.len()).map(|_| None).collect(), }; for (i, arg) in args.into_iter().enumerate() { - let index = mir.local_index(&mir::Lvalue::Arg(mir::Arg::new(i))).unwrap(); + // Locals after local 0 are the function arguments + let index = mir::Local::new(i + 1); context.locals[index] = Some(arg); } context @@ -238,7 +239,7 @@ impl<'a, 'tcx> MirConstContext<'a, 'tcx> { fn trans_def(ccx: &'a CrateContext<'a, 'tcx>, mut instance: Instance<'tcx>, - args: IndexVec>) + args: IndexVec>) -> Result, ConstEvalErr> { // Try to resolve associated constants. if let Some(trait_id) = ccx.tcx().trait_of_item(instance.def) { @@ -260,9 +261,7 @@ impl<'a, 'tcx> MirConstContext<'a, 'tcx> { } } - let mir = ccx.get_mir(instance.def).unwrap_or_else(|| { - bug!("missing constant MIR for {}", instance) - }); + let mir = ccx.tcx().item_mir(instance.def); MirConstContext::new(ccx, &mir, instance.substs, args).trans() } @@ -311,8 +310,7 @@ impl<'a, 'tcx> MirConstContext<'a, 'tcx> { mir::TerminatorKind::Goto { target } => target, mir::TerminatorKind::Return => { failure?; - let index = self.mir.local_index(&mir::Lvalue::ReturnPointer).unwrap(); - return Ok(self.locals[index].unwrap_or_else(|| { + return Ok(self.locals[mir::RETURN_POINTER].unwrap_or_else(|| { span_bug!(span, "no returned value in constant"); })); } @@ -376,7 +374,7 @@ impl<'a, 'tcx> MirConstContext<'a, 'tcx> { } fn store(&mut self, dest: &mir::Lvalue<'tcx>, value: Const<'tcx>, span: Span) { - if let Some(index) = self.mir.local_index(dest) { + if let mir::Lvalue::Local(index) = *dest { self.locals[index] = Some(value); } else { span_bug!(span, "assignment to {:?} in constant", dest); @@ -387,17 +385,14 @@ impl<'a, 'tcx> MirConstContext<'a, 'tcx> { -> Result, ConstEvalErr> { let tcx = self.ccx.tcx(); - if let Some(index) = self.mir.local_index(lvalue) { + if let mir::Lvalue::Local(index) = *lvalue { return Ok(self.locals[index].unwrap_or_else(|| { span_bug!(span, "{:?} not initialized", lvalue) }).as_lvalue()); } let lvalue = match *lvalue { - mir::Lvalue::Var(_) | - mir::Lvalue::Temp(_) | - mir::Lvalue::Arg(_) | - mir::Lvalue::ReturnPointer => bug!(), // handled above + mir::Lvalue::Local(_) => bug!(), // handled above mir::Lvalue::Static(def_id) => { ConstLvalue { base: Base::Static(consts::get_static(self.ccx, def_id)), @@ -572,7 +567,7 @@ impl<'a, 'tcx> MirConstContext<'a, 'tcx> { } match *kind { - mir::AggregateKind::Vec => { + mir::AggregateKind::Array => { self.const_array(dest_ty, &fields) } mir::AggregateKind::Adt(..) | @@ -776,7 +771,7 @@ impl<'a, 'tcx> MirConstContext<'a, 'tcx> { let rhs = self.const_operand(rhs, span)?; let ty = lhs.ty; let val_ty = op.ty(tcx, lhs.ty, rhs.ty); - let binop_ty = tcx.mk_tup(vec![val_ty, tcx.types.bool]); + let binop_ty = tcx.intern_tup(&[val_ty, tcx.types.bool]); let (lhs, rhs) = (lhs.llval, rhs.llval); assert!(!ty.is_fp()); diff --git a/src/librustc_trans/mir/lvalue.rs b/src/librustc_trans/mir/lvalue.rs index 0ce5544c3b..d28c466e23 100644 --- a/src/librustc_trans/mir/lvalue.rs +++ b/src/librustc_trans/mir/lvalue.rs @@ -10,13 +10,11 @@ use llvm::ValueRef; use rustc::ty::{self, Ty, TypeFoldable}; -use rustc::mir::repr as mir; +use rustc::mir; use rustc::mir::tcx::LvalueTy; use rustc_data_structures::indexed_vec::Idx; -use abi; use adt; use base; -use builder::Builder; use common::{self, BlockAndBuilder, CrateContext, C_uint, C_undef}; use consts; use machine; @@ -69,18 +67,6 @@ impl<'tcx> LvalueRef<'tcx> { } } -pub fn get_meta(b: &Builder, fat_ptr: ValueRef) -> ValueRef { - b.struct_gep(fat_ptr, abi::FAT_PTR_EXTRA) -} - -pub fn get_dataptr(b: &Builder, fat_ptr: ValueRef) -> ValueRef { - b.struct_gep(fat_ptr, abi::FAT_PTR_ADDR) -} - -pub fn load_fat_ptr(b: &Builder, fat_ptr: ValueRef) -> (ValueRef, ValueRef) { - (b.load(get_dataptr(b, fat_ptr)), b.load(get_meta(b, fat_ptr))) -} - impl<'bcx, 'tcx> MirContext<'bcx, 'tcx> { pub fn trans_lvalue(&mut self, bcx: &BlockAndBuilder<'bcx, 'tcx>, @@ -91,7 +77,7 @@ impl<'bcx, 'tcx> MirContext<'bcx, 'tcx> { let ccx = bcx.ccx(); let tcx = bcx.tcx(); - if let Some(index) = self.mir.local_index(lvalue) { + if let mir::Lvalue::Local(index) = *lvalue { match self.locals[index] { LocalRef::Lvalue(lvalue) => { return lvalue; @@ -103,10 +89,7 @@ impl<'bcx, 'tcx> MirContext<'bcx, 'tcx> { } let result = match *lvalue { - mir::Lvalue::Var(_) | - mir::Lvalue::Temp(_) | - mir::Lvalue::Arg(_) | - mir::Lvalue::ReturnPointer => bug!(), // handled above + mir::Lvalue::Local(_) => bug!(), // handled above mir::Lvalue::Static(def_id) => { let const_ty = self.monomorphized_lvalue_ty(lvalue); LvalueRef::new_sized(consts::get_static(ccx, def_id), @@ -235,7 +218,7 @@ impl<'bcx, 'tcx> MirContext<'bcx, 'tcx> { lvalue: &mir::Lvalue<'tcx>, f: F) -> U where F: FnOnce(&mut Self, LvalueRef<'tcx>) -> U { - if let Some(index) = self.mir.local_index(lvalue) { + if let mir::Lvalue::Local(index) = *lvalue { match self.locals[index] { LocalRef::Lvalue(lvalue) => f(self, lvalue), LocalRef::Operand(None) => { diff --git a/src/librustc_trans/mir/mod.rs b/src/librustc_trans/mir/mod.rs index 37ce31a3c4..d2adf88c91 100644 --- a/src/librustc_trans/mir/mod.rs +++ b/src/librustc_trans/mir/mod.rs @@ -11,7 +11,7 @@ use libc::c_uint; use llvm::{self, ValueRef}; use rustc::ty; -use rustc::mir::repr as mir; +use rustc::mir; use rustc::mir::tcx::LvalueTy; use session::config::FullDebugInfo; use base; @@ -21,9 +21,9 @@ use machine; use type_of; use syntax_pos::{DUMMY_SP, NO_EXPANSION, COMMAND_LINE_EXPN, BytePos}; +use syntax::parse::token::keywords; -use std::ops::Deref; -use std::rc::Rc; +use std::cell::Ref; use std::iter; use basic_block::BasicBlock; @@ -33,30 +33,14 @@ use rustc_data_structures::indexed_vec::{IndexVec, Idx}; pub use self::constant::trans_static_initializer; -use self::lvalue::{LvalueRef, get_dataptr, get_meta}; +use self::lvalue::{LvalueRef}; use rustc::mir::traversal; use self::operand::{OperandRef, OperandValue}; -#[derive(Clone)] -pub enum CachedMir<'mir, 'tcx: 'mir> { - Ref(&'mir mir::Mir<'tcx>), - Owned(Rc>) -} - -impl<'mir, 'tcx: 'mir> Deref for CachedMir<'mir, 'tcx> { - type Target = mir::Mir<'tcx>; - fn deref(&self) -> &mir::Mir<'tcx> { - match *self { - CachedMir::Ref(r) => r, - CachedMir::Owned(ref rc) => rc - } - } -} - /// Master context for translating MIR. pub struct MirContext<'bcx, 'tcx:'bcx> { - mir: CachedMir<'bcx, 'tcx>, + mir: Ref<'tcx, mir::Mir<'tcx>>, /// Function context fcx: &'bcx common::FunctionContext<'bcx, 'tcx>, @@ -222,7 +206,7 @@ pub fn trans_mir<'blk, 'tcx: 'blk>(fcx: &'blk FunctionContext<'blk, 'tcx>) { let scopes = debuginfo::create_mir_scopes(fcx); let mut mircx = MirContext { - mir: mir.clone(), + mir: Ref::clone(&mir), fcx: fcx, llpersonalityslot: None, blocks: block_bcxs, @@ -236,51 +220,61 @@ pub fn trans_mir<'blk, 'tcx: 'blk>(fcx: &'blk FunctionContext<'blk, 'tcx>) { // Allocate variable and temp allocas mircx.locals = { let args = arg_local_refs(&bcx, &mir, &mircx.scopes, &lvalue_locals); - let vars = mir.var_decls.iter().enumerate().map(|(i, decl)| { + + let mut allocate_local = |local| { + let decl = &mir.local_decls[local]; let ty = bcx.monomorphize(&decl.ty); - let debug_scope = mircx.scopes[decl.source_info.scope]; - let dbg = debug_scope.is_valid() && bcx.sess().opts.debuginfo == FullDebugInfo; - let local = mir.local_index(&mir::Lvalue::Var(mir::Var::new(i))).unwrap(); - if !lvalue_locals.contains(local.index()) && !dbg { - return LocalRef::new_operand(bcx.ccx(), ty); - } + if let Some(name) = decl.name { + // User variable + let source_info = decl.source_info.unwrap(); + let debug_scope = mircx.scopes[source_info.scope]; + let dbg = debug_scope.is_valid() && bcx.sess().opts.debuginfo == FullDebugInfo; - let lvalue = LvalueRef::alloca(&bcx, ty, &decl.name.as_str()); - if dbg { - let dbg_loc = mircx.debug_loc(decl.source_info); - if let DebugLoc::ScopeAt(scope, span) = dbg_loc { - bcx.with_block(|bcx| { - declare_local(bcx, decl.name, ty, scope, - VariableAccess::DirectVariable { alloca: lvalue.llval }, - VariableKind::LocalVariable, span); - }); - } else { - panic!("Unexpected"); + if !lvalue_locals.contains(local.index()) && !dbg { + debug!("alloc: {:?} ({}) -> operand", local, name); + return LocalRef::new_operand(bcx.ccx(), ty); } - } - LocalRef::Lvalue(lvalue) - }); - - let locals = mir.temp_decls.iter().enumerate().map(|(i, decl)| { - (mir::Lvalue::Temp(mir::Temp::new(i)), decl.ty) - }).chain(iter::once((mir::Lvalue::ReturnPointer, mir.return_ty))); - - args.into_iter().chain(vars).chain(locals.map(|(lvalue, ty)| { - let ty = bcx.monomorphize(&ty); - let local = mir.local_index(&lvalue).unwrap(); - if lvalue == mir::Lvalue::ReturnPointer && fcx.fn_ty.ret.is_indirect() { - let llretptr = llvm::get_param(fcx.llfn, 0); - LocalRef::Lvalue(LvalueRef::new_sized(llretptr, LvalueTy::from_ty(ty))) - } else if lvalue_locals.contains(local.index()) { - LocalRef::Lvalue(LvalueRef::alloca(&bcx, ty, &format!("{:?}", lvalue))) + + debug!("alloc: {:?} ({}) -> lvalue", local, name); + let lvalue = LvalueRef::alloca(&bcx, ty, &name.as_str()); + if dbg { + let dbg_loc = mircx.debug_loc(source_info); + if let DebugLoc::ScopeAt(scope, span) = dbg_loc { + bcx.with_block(|bcx| { + declare_local(bcx, name, ty, scope, + VariableAccess::DirectVariable { alloca: lvalue.llval }, + VariableKind::LocalVariable, span); + }); + } else { + panic!("Unexpected"); + } + } + LocalRef::Lvalue(lvalue) } else { - // If this is an immediate local, we do not create an - // alloca in advance. Instead we wait until we see the - // definition and update the operand there. - LocalRef::new_operand(bcx.ccx(), ty) + // Temporary or return pointer + if local == mir::RETURN_POINTER && fcx.fn_ty.ret.is_indirect() { + debug!("alloc: {:?} (return pointer) -> lvalue", local); + let llretptr = llvm::get_param(fcx.llfn, 0); + LocalRef::Lvalue(LvalueRef::new_sized(llretptr, LvalueTy::from_ty(ty))) + } else if lvalue_locals.contains(local.index()) { + debug!("alloc: {:?} -> lvalue", local); + LocalRef::Lvalue(LvalueRef::alloca(&bcx, ty, &format!("{:?}", local))) + } else { + // If this is an immediate local, we do not create an + // alloca in advance. Instead we wait until we see the + // definition and update the operand there. + debug!("alloc: {:?} -> operand", local); + LocalRef::new_operand(bcx.ccx(), ty) + } } - })).collect() + }; + + let retptr = allocate_local(mir::RETURN_POINTER); + iter::once(retptr) + .chain(args.into_iter()) + .chain(mir.vars_and_temps_iter().map(allocate_local)) + .collect() }; // Branch to the START block @@ -345,10 +339,11 @@ fn arg_local_refs<'bcx, 'tcx>(bcx: &BlockAndBuilder<'bcx, 'tcx>, None }; - mir.arg_decls.iter().enumerate().map(|(arg_index, arg_decl)| { + mir.args_iter().enumerate().map(|(arg_index, local)| { + let arg_decl = &mir.local_decls[local]; let arg_ty = bcx.monomorphize(&arg_decl.ty); - let local = mir.local_index(&mir::Lvalue::Arg(mir::Arg::new(arg_index))).unwrap(); - if arg_decl.spread { + + if Some(local) == mir.spread_arg { // This argument (e.g. the last argument in the "rust-call" ABI) // is a tuple that was spread at the ABI level and now we have // to reconstruct it into a tuple local variable, from multiple @@ -371,8 +366,10 @@ fn arg_local_refs<'bcx, 'tcx>(bcx: &BlockAndBuilder<'bcx, 'tcx>, // they are the two sub-fields of a single aggregate field. let meta = &fcx.fn_ty.args[idx]; idx += 1; - arg.store_fn_arg(bcx, &mut llarg_idx, get_dataptr(bcx, dst)); - meta.store_fn_arg(bcx, &mut llarg_idx, get_meta(bcx, dst)); + arg.store_fn_arg(bcx, &mut llarg_idx, + base::get_dataptr_builder(bcx, dst)); + meta.store_fn_arg(bcx, &mut llarg_idx, + base::get_meta_builder(bcx, dst)); } else { arg.store_fn_arg(bcx, &mut llarg_idx, dst); } @@ -384,7 +381,7 @@ fn arg_local_refs<'bcx, 'tcx>(bcx: &BlockAndBuilder<'bcx, 'tcx>, let variable_access = VariableAccess::DirectVariable { alloca: lltemp }; - declare_local(bcx, arg_decl.debug_name, + declare_local(bcx, arg_decl.name.unwrap_or(keywords::Invalid.name()), arg_ty, scope, variable_access, VariableKind::ArgumentVariable(arg_index + 1), bcx.fcx().span.unwrap_or(DUMMY_SP)); @@ -446,8 +443,10 @@ fn arg_local_refs<'bcx, 'tcx>(bcx: &BlockAndBuilder<'bcx, 'tcx>, // so make an alloca to store them in. let meta = &fcx.fn_ty.args[idx]; idx += 1; - arg.store_fn_arg(bcx, &mut llarg_idx, get_dataptr(bcx, lltemp)); - meta.store_fn_arg(bcx, &mut llarg_idx, get_meta(bcx, lltemp)); + arg.store_fn_arg(bcx, &mut llarg_idx, + base::get_dataptr_builder(bcx, lltemp)); + meta.store_fn_arg(bcx, &mut llarg_idx, + base::get_meta_builder(bcx, lltemp)); } else { // otherwise, arg is passed by value, so make a // temporary and store it there @@ -458,8 +457,8 @@ fn arg_local_refs<'bcx, 'tcx>(bcx: &BlockAndBuilder<'bcx, 'tcx>, bcx.with_block(|bcx| arg_scope.map(|scope| { // Is this a regular argument? if arg_index > 0 || mir.upvar_decls.is_empty() { - declare_local(bcx, arg_decl.debug_name, arg_ty, scope, - VariableAccess::DirectVariable { alloca: llval }, + declare_local(bcx, arg_decl.name.unwrap_or(keywords::Invalid.name()), arg_ty, + scope, VariableAccess::DirectVariable { alloca: llval }, VariableKind::ArgumentVariable(arg_index + 1), bcx.fcx().span.unwrap_or(DUMMY_SP)); return; diff --git a/src/librustc_trans/mir/operand.rs b/src/librustc_trans/mir/operand.rs index 270033be93..62eda56e2e 100644 --- a/src/librustc_trans/mir/operand.rs +++ b/src/librustc_trans/mir/operand.rs @@ -10,7 +10,7 @@ use llvm::ValueRef; use rustc::ty::Ty; -use rustc::mir::repr as mir; +use rustc::mir; use rustc_data_structures::indexed_vec::Idx; use base; @@ -143,20 +143,18 @@ impl<'bcx, 'tcx> MirContext<'bcx, 'tcx> { { debug!("trans_load: {:?} @ {:?}", Value(llval), ty); - let val = if common::type_is_imm_pair(bcx.ccx(), ty) { + let val = if common::type_is_fat_ptr(bcx.tcx(), ty) { + let (lldata, llextra) = base::load_fat_ptr_builder(bcx, llval, ty); + OperandValue::Pair(lldata, llextra) + } else if common::type_is_imm_pair(bcx.ccx(), ty) { + let [a_ty, b_ty] = common::type_pair_fields(bcx.ccx(), ty).unwrap(); let a_ptr = bcx.struct_gep(llval, 0); let b_ptr = bcx.struct_gep(llval, 1); - // This is None only for fat pointers, which don't - // need any special load-time behavior anyway. - let pair_fields = common::type_pair_fields(bcx.ccx(), ty); - let (a, b) = if let Some([a_ty, b_ty]) = pair_fields { - (base::load_ty_builder(bcx, a_ptr, a_ty), - base::load_ty_builder(bcx, b_ptr, b_ty)) - } else { - (bcx.load(a_ptr), bcx.load(b_ptr)) - }; - OperandValue::Pair(a, b) + OperandValue::Pair( + base::load_ty_builder(bcx, a_ptr, a_ty), + base::load_ty_builder(bcx, b_ptr, b_ty) + ) } else if common::type_is_immediate(bcx.ccx(), ty) { OperandValue::Immediate(base::load_ty_builder(bcx, llval, ty)) } else { @@ -175,7 +173,7 @@ impl<'bcx, 'tcx> MirContext<'bcx, 'tcx> { // watch out for locals that do not have an // alloca; they are handled somewhat differently - if let Some(index) = self.mir.local_index(lvalue) { + if let mir::Lvalue::Local(index) = *lvalue { match self.locals[index] { LocalRef::Operand(Some(o)) => { return o; @@ -191,7 +189,7 @@ impl<'bcx, 'tcx> MirContext<'bcx, 'tcx> { // Moves out of pair fields are trivial. if let &mir::Lvalue::Projection(ref proj) = lvalue { - if let Some(index) = self.mir.local_index(&proj.base) { + if let mir::Lvalue::Local(index) = proj.base { if let LocalRef::Operand(Some(o)) = self.locals[index] { match (o.val, &proj.elem) { (OperandValue::Pair(a, b), diff --git a/src/librustc_trans/mir/rvalue.rs b/src/librustc_trans/mir/rvalue.rs index b643dcd987..f25877b1de 100644 --- a/src/librustc_trans/mir/rvalue.rs +++ b/src/librustc_trans/mir/rvalue.rs @@ -11,15 +11,18 @@ use llvm::{self, ValueRef}; use rustc::ty::{self, Ty}; use rustc::ty::cast::{CastTy, IntTy}; -use rustc::mir::repr as mir; +use rustc::ty::layout::Layout; +use rustc::mir; use asm; use base; use callee::Callee; use common::{self, val_ty, C_bool, C_null, C_uint, BlockAndBuilder, Result}; +use common::{C_integral}; use debuginfo::DebugLoc; use adt; use machine; +use type_::Type; use type_of; use tvec; use value::Value; @@ -28,7 +31,7 @@ use Disr; use super::MirContext; use super::constant::const_scalar_checked_binop; use super::operand::{OperandRef, OperandValue}; -use super::lvalue::{LvalueRef, get_dataptr}; +use super::lvalue::{LvalueRef}; impl<'bcx, 'tcx> MirContext<'bcx, 'tcx> { pub fn trans_rvalue(&mut self, @@ -98,7 +101,7 @@ impl<'bcx, 'tcx> MirContext<'bcx, 'tcx> { let tr_elem = self.trans_operand(&bcx, elem); let size = count.value.as_u64(bcx.tcx().sess.target.uint_type); let size = C_uint(bcx.ccx(), size); - let base = get_dataptr(&bcx, dest.llval); + let base = base::get_dataptr_builder(&bcx, dest.llval); let bcx = bcx.map_block(|block| { tvec::slice_for_each(block, base, tr_elem.ty, size, |block, llslot| { self.store_operand_direct(block, llslot, tr_elem); @@ -281,7 +284,26 @@ impl<'bcx, 'tcx> MirContext<'bcx, 'tcx> { } OperandValue::Pair(..) => bug!("Unexpected Pair operand") }; - (discr, adt::is_discr_signed(&l)) + let (signed, min, max) = match l { + &Layout::CEnum { signed, min, max, .. } => { + (signed, min, max) + } + _ => bug!("CEnum {:?} is not an enum", operand) + }; + + if max > min { + // We want `table[e as usize]` to not + // have bound checks, and this is the most + // convenient place to put the `assume`. + + base::call_assume(&bcx, bcx.icmp( + llvm::IntULE, + discr, + C_integral(common::val_ty(discr), max, false) + )) + } + + (discr, signed) } else { (operand.immediate(), operand.ty.is_signed()) }; @@ -382,13 +404,10 @@ impl<'bcx, 'tcx> MirContext<'bcx, 'tcx> { match (lhs.val, rhs.val) { (OperandValue::Pair(lhs_addr, lhs_extra), OperandValue::Pair(rhs_addr, rhs_extra)) => { - bcx.with_block(|bcx| { - base::compare_fat_ptrs(bcx, - lhs_addr, lhs_extra, - rhs_addr, rhs_extra, - lhs.ty, op.to_hir_binop(), - debug_loc) - }) + self.trans_fat_ptr_binop(&bcx, op, + lhs_addr, lhs_extra, + rhs_addr, rhs_extra, + lhs.ty) } _ => bug!() } @@ -411,7 +430,7 @@ impl<'bcx, 'tcx> MirContext<'bcx, 'tcx> { lhs.immediate(), rhs.immediate(), lhs.ty); let val_ty = op.ty(bcx.tcx(), lhs.ty, rhs.ty); - let operand_ty = bcx.tcx().mk_tup(vec![val_ty, bcx.tcx().types.bool]); + let operand_ty = bcx.tcx().intern_tup(&[val_ty, bcx.tcx().types.bool]); let operand = OperandRef { val: result, ty: operand_ty @@ -485,6 +504,8 @@ impl<'bcx, 'tcx> MirContext<'bcx, 'tcx> { input_ty: Ty<'tcx>) -> ValueRef { let is_float = input_ty.is_fp(); let is_signed = input_ty.is_signed(); + let is_nil = input_ty.is_nil(); + let is_bool = input_ty.is_bool(); match op { mir::BinOp::Add => if is_float { bcx.fadd(lhs, rhs) @@ -535,12 +556,79 @@ impl<'bcx, 'tcx> MirContext<'bcx, 'tcx> { DebugLoc::None) }) } - mir::BinOp::Eq | mir::BinOp::Lt | mir::BinOp::Gt | - mir::BinOp::Ne | mir::BinOp::Le | mir::BinOp::Ge => { - bcx.with_block(|bcx| { - base::compare_scalar_types(bcx, lhs, rhs, input_ty, - op.to_hir_binop(), DebugLoc::None) + mir::BinOp::Ne | mir::BinOp::Lt | mir::BinOp::Gt | + mir::BinOp::Eq | mir::BinOp::Le | mir::BinOp::Ge => if is_nil { + C_bool(bcx.ccx(), match op { + mir::BinOp::Ne | mir::BinOp::Lt | mir::BinOp::Gt => false, + mir::BinOp::Eq | mir::BinOp::Le | mir::BinOp::Ge => true, + _ => unreachable!() }) + } else if is_float { + bcx.fcmp( + base::bin_op_to_fcmp_predicate(op.to_hir_binop()), + lhs, rhs + ) + } else { + let (lhs, rhs) = if is_bool { + // FIXME(#36856) -- extend the bools into `i8` because + // LLVM's i1 comparisons are broken. + (bcx.zext(lhs, Type::i8(bcx.ccx())), + bcx.zext(rhs, Type::i8(bcx.ccx()))) + } else { + (lhs, rhs) + }; + + bcx.icmp( + base::bin_op_to_icmp_predicate(op.to_hir_binop(), is_signed), + lhs, rhs + ) + } + } + } + + pub fn trans_fat_ptr_binop(&mut self, + bcx: &BlockAndBuilder<'bcx, 'tcx>, + op: mir::BinOp, + lhs_addr: ValueRef, + lhs_extra: ValueRef, + rhs_addr: ValueRef, + rhs_extra: ValueRef, + _input_ty: Ty<'tcx>) + -> ValueRef { + match op { + mir::BinOp::Eq => { + bcx.and( + bcx.icmp(llvm::IntEQ, lhs_addr, rhs_addr), + bcx.icmp(llvm::IntEQ, lhs_extra, rhs_extra) + ) + } + mir::BinOp::Ne => { + bcx.or( + bcx.icmp(llvm::IntNE, lhs_addr, rhs_addr), + bcx.icmp(llvm::IntNE, lhs_extra, rhs_extra) + ) + } + mir::BinOp::Le | mir::BinOp::Lt | + mir::BinOp::Ge | mir::BinOp::Gt => { + // a OP b ~ a.0 STRICT(OP) b.0 | (a.0 == b.0 && a.1 OP a.1) + let (op, strict_op) = match op { + mir::BinOp::Lt => (llvm::IntULT, llvm::IntULT), + mir::BinOp::Le => (llvm::IntULE, llvm::IntULT), + mir::BinOp::Gt => (llvm::IntUGT, llvm::IntUGT), + mir::BinOp::Ge => (llvm::IntUGE, llvm::IntUGT), + _ => bug!(), + }; + + bcx.or( + bcx.icmp(strict_op, lhs_addr, rhs_addr), + bcx.and( + bcx.icmp(llvm::IntEQ, lhs_addr, rhs_addr), + bcx.icmp(op, lhs_extra, rhs_extra) + ) + ) + } + _ => { + bug!("unexpected fat ptr binop"); } } } diff --git a/src/librustc_trans/mir/statement.rs b/src/librustc_trans/mir/statement.rs index 9943acbc88..296a0e8049 100644 --- a/src/librustc_trans/mir/statement.rs +++ b/src/librustc_trans/mir/statement.rs @@ -8,7 +8,7 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -use rustc::mir::repr as mir; +use rustc::mir; use base; use common::{self, BlockAndBuilder}; @@ -30,7 +30,7 @@ impl<'bcx, 'tcx> MirContext<'bcx, 'tcx> { debug_loc.apply(bcx.fcx()); match statement.kind { mir::StatementKind::Assign(ref lvalue, ref rvalue) => { - if let Some(index) = self.mir.local_index(lvalue) { + if let mir::Lvalue::Local(index) = *lvalue { match self.locals[index] { LocalRef::Lvalue(tr_dest) => { self.trans_rvalue(bcx, tr_dest, rvalue, debug_loc) @@ -86,7 +86,7 @@ impl<'bcx, 'tcx> MirContext<'bcx, 'tcx> { lvalue: &mir::Lvalue<'tcx>, intrinsic: base::Lifetime) -> BlockAndBuilder<'bcx, 'tcx> { - if let Some(index) = self.mir.local_index(lvalue) { + if let mir::Lvalue::Local(index) = *lvalue { if let LocalRef::Lvalue(tr_lval) = self.locals[index] { intrinsic.call(&bcx, tr_lval.llval); } diff --git a/src/librustc_trans/trans_item.rs b/src/librustc_trans/trans_item.rs index 131df50217..8930387c04 100644 --- a/src/librustc_trans/trans_item.rs +++ b/src/librustc_trans/trans_item.rs @@ -28,7 +28,6 @@ use rustc::hir::def_id::DefId; use rustc::ty::{self, Ty, TyCtxt, TypeFoldable}; use rustc::ty::subst::Substs; use rustc_const_eval::fatal_const_eval_err; -use std::hash::{Hash, Hasher}; use syntax::ast::{self, NodeId}; use syntax::attr; use type_of; @@ -36,33 +35,13 @@ use glue; use abi::{Abi, FnType}; use back::symbol_names; -#[derive(PartialEq, Eq, Clone, Copy, Debug)] +#[derive(PartialEq, Eq, Clone, Copy, Debug, Hash)] pub enum TransItem<'tcx> { DropGlue(DropGlueKind<'tcx>), Fn(Instance<'tcx>), Static(NodeId) } -impl<'tcx> Hash for TransItem<'tcx> { - fn hash(&self, s: &mut H) { - match *self { - TransItem::DropGlue(t) => { - 0u8.hash(s); - t.hash(s); - }, - TransItem::Fn(instance) => { - 1u8.hash(s); - instance.def.hash(s); - (instance.substs as *const _ as usize).hash(s); - } - TransItem::Static(node_id) => { - 2u8.hash(s); - node_id.hash(s); - } - }; - } -} - impl<'a, 'tcx> TransItem<'tcx> { pub fn define(&self, ccx: &CrateContext<'a, 'tcx>) { @@ -331,7 +310,7 @@ impl<'a, 'tcx> TransItem<'tcx> { }, TransItem::Static(node_id) => { let def_id = hir_map.local_def_id(node_id); - let instance = Instance::new(def_id, Substs::empty(tcx)); + let instance = Instance::new(def_id, tcx.intern_substs(&[])); to_string_internal(tcx, "static ", instance) }, }; @@ -359,7 +338,7 @@ impl<'a, 'tcx> TransItem<'tcx> { TransItem::Fn(instance) => { format!("Fn({:?}, {})", instance.def, - instance.substs as *const _ as usize) + instance.substs.as_ptr() as usize) } TransItem::Static(id) => { format!("Static({:?})", id) diff --git a/src/librustc_typeck/astconv.rs b/src/librustc_typeck/astconv.rs index f5e289c330..c93f1c6c8e 100644 --- a/src/librustc_typeck/astconv.rs +++ b/src/librustc_typeck/astconv.rs @@ -55,7 +55,7 @@ use hir::def_id::DefId; use hir::print as pprust; use middle::resolve_lifetime as rl; use rustc::lint; -use rustc::ty::subst::{Subst, Substs}; +use rustc::ty::subst::{Kind, Subst, Substs}; use rustc::traits; use rustc::ty::{self, Ty, TyCtxt, ToPredicate, TypeFoldable}; use rustc::ty::wf::object_region_bounds; @@ -124,7 +124,7 @@ pub trait AstConv<'gcx, 'tcx> { /// Same as ty_infer, but with a known type parameter definition. fn ty_infer_for_def(&self, _def: &ty::TypeParameterDef<'tcx>, - _substs: &Substs<'tcx>, + _substs: &[Kind<'tcx>], span: Span) -> Ty<'tcx> { self.ty_infer(span) } @@ -171,8 +171,6 @@ struct ConvertedBinding<'tcx> { span: Span, } -type TraitAndProjections<'tcx> = (ty::PolyTraitRef<'tcx>, Vec>); - /// Dummy type used for the `Self` of a `TraitRef` created for converting /// a trait object, and which gets removed in `ExistentialTraitRef`. /// This type must not appear anywhere in other converted types. @@ -561,15 +559,16 @@ impl<'o, 'gcx: 'tcx, 'tcx> AstConv<'gcx, 'tcx>+'o { /// Returns the appropriate lifetime to use for any output lifetimes /// (if one exists) and a vector of the (pattern, number of lifetimes) /// corresponding to each input type/pattern. - fn find_implied_output_region(&self, - input_tys: &[Ty<'tcx>], - input_pats: Vec) -> ElidedLifetime + fn find_implied_output_region(&self, + input_tys: &[Ty<'tcx>], + input_pats: F) -> ElidedLifetime + where F: FnOnce() -> Vec { let tcx = self.tcx(); let mut lifetimes_for_params = Vec::new(); let mut possible_implied_output_region = None; - for (input_type, input_pat) in input_tys.iter().zip(input_pats) { + for input_type in input_tys.iter() { let mut regions = FnvHashSet(); let have_bound_regions = tcx.collect_regions(input_type, &mut regions); @@ -583,8 +582,11 @@ impl<'o, 'gcx: 'tcx, 'tcx> AstConv<'gcx, 'tcx>+'o { possible_implied_output_region = regions.iter().cloned().next(); } + // Use a placeholder for `name` because computing it can be + // expensive and we don't want to do it until we know it's + // necessary. lifetimes_for_params.push(ElisionFailureInfo { - name: input_pat, + name: String::new(), lifetime_count: regions.len(), have_bound_regions: have_bound_regions }); @@ -593,6 +595,11 @@ impl<'o, 'gcx: 'tcx, 'tcx> AstConv<'gcx, 'tcx>+'o { if lifetimes_for_params.iter().map(|e| e.lifetime_count).sum::() == 1 { Ok(*possible_implied_output_region.unwrap()) } else { + // Fill in the expensive `name` fields now that we know they're + // needed. + for (info, input_pat) in lifetimes_for_params.iter_mut().zip(input_pats()) { + info.name = input_pat; + } Err(Some(lifetimes_for_params)) } } @@ -620,16 +627,17 @@ impl<'o, 'gcx: 'tcx, 'tcx> AstConv<'gcx, 'tcx>+'o { fn convert_parenthesized_parameters(&self, rscope: &RegionScope, - region_substs: &Substs<'tcx>, + region_substs: &[Kind<'tcx>], data: &hir::ParenthesizedParameterData) -> (Ty<'tcx>, ConvertedBinding<'tcx>) { let anon_scope = rscope.anon_type_scope(); let binding_rscope = MaybeWithAnonTypes::new(BindingRscope::new(), anon_scope); - let inputs: Vec<_> = data.inputs.iter().map(|a_t| { + let inputs = self.tcx().mk_type_list(data.inputs.iter().map(|a_t| { self.ast_ty_arg_to_ty(&binding_rscope, None, region_substs, a_t) - }).collect(); - let input_params = vec![String::new(); inputs.len()]; + })); + let inputs_len = inputs.len(); + let input_params = || vec![String::new(); inputs_len]; let implied_output_region = self.find_implied_output_region(&inputs, input_params); let (output, output_span) = match data.output { @@ -650,7 +658,7 @@ impl<'o, 'gcx: 'tcx, 'tcx> AstConv<'gcx, 'tcx>+'o { span: output_span }; - (self.tcx().mk_tup(inputs), output_binding) + (self.tcx().mk_ty(ty::TyTuple(inputs)), output_binding) } pub fn instantiate_poly_trait_ref(&self, @@ -1241,14 +1249,28 @@ impl<'o, 'gcx: 'tcx, 'tcx> AstConv<'gcx, 'tcx>+'o { -> Result, ErrorReported> { if bounds.is_empty() { - span_err!(self.tcx().sess, span, E0220, + struct_span_err!(self.tcx().sess, span, E0220, "associated type `{}` not found for `{}`", assoc_name, - ty_param_name); + ty_param_name) + .span_label(span, &format!("associated type `{}` not found", assoc_name)) + .emit(); return Err(ErrorReported); } if bounds.len() > 1 { + let spans = bounds.iter().map(|b| { + self.tcx().impl_or_trait_items(b.def_id()).iter() + .find(|&&def_id| { + match self.tcx().impl_or_trait_item(def_id) { + ty::TypeTraitItem(ref item) => item.name.as_str() == assoc_name, + _ => false + } + }) + .and_then(|&def_id| self.tcx().map.as_local_node_id(def_id)) + .and_then(|node_id| self.tcx().map.opt_span(node_id)) + }); + let mut err = struct_span_err!( self.tcx().sess, span, E0221, "ambiguous associated type `{}` in bounds of `{}`", @@ -1256,11 +1278,17 @@ impl<'o, 'gcx: 'tcx, 'tcx> AstConv<'gcx, 'tcx>+'o { ty_param_name); err.span_label(span, &format!("ambiguous associated type `{}`", assoc_name)); - for bound in &bounds { - span_note!(&mut err, span, - "associated type `{}` could derive from `{}`", - ty_param_name, - bound); + for span_and_bound in spans.zip(&bounds) { + if let Some(span) = span_and_bound.0 { + err.span_label(span, &format!("ambiguous `{}` from `{}`", + assoc_name, + span_and_bound.1)); + } else { + span_note!(&mut err, span, + "associated type `{}` could derive from `{}`", + ty_param_name, + span_and_bound.1); + } } err.emit(); } @@ -1429,7 +1457,7 @@ impl<'o, 'gcx: 'tcx, 'tcx> AstConv<'gcx, 'tcx>+'o { fn ast_ty_arg_to_ty(&self, rscope: &RegionScope, def: Option<&ty::TypeParameterDef<'tcx>>, - region_substs: &Substs<'tcx>, + region_substs: &[Kind<'tcx>], ast_ty: &hir::Ty) -> Ty<'tcx> { @@ -1454,7 +1482,8 @@ impl<'o, 'gcx: 'tcx, 'tcx> AstConv<'gcx, 'tcx>+'o { def: Def, opt_self_ty: Option>, base_path_ref_id: ast::NodeId, - base_segments: &[hir::PathSegment]) + base_segments: &[hir::PathSegment], + permit_variants: bool) -> Ty<'tcx> { let tcx = self.tcx(); @@ -1485,6 +1514,16 @@ impl<'o, 'gcx: 'tcx, 'tcx> AstConv<'gcx, 'tcx>+'o { did, base_segments.last().unwrap()) } + Def::Variant(did) if permit_variants => { + // Convert "variant type" as if it were a real type. + // The resulting `Ty` is type of the variant's enum for now. + tcx.prohibit_type_params(base_segments.split_last().unwrap().1); + self.ast_path_to_ty(rscope, + span, + param_mode, + tcx.parent_def_id(did).unwrap(), + base_segments.last().unwrap()) + } Def::TyParam(did) => { tcx.prohibit_type_params(base_segments); @@ -1510,7 +1549,7 @@ impl<'o, 'gcx: 'tcx, 'tcx> AstConv<'gcx, 'tcx>+'o { tcx.prohibit_type_params(base_segments); let impl_id = tcx.map.as_local_node_id(def_id).unwrap(); - let ty = tcx.node_id_to_type(impl_id); + let ty = tcx.tables().node_id_to_type(impl_id); if let Some(free_substs) = self.get_free_substs() { ty.subst(tcx, free_substs) } else { @@ -1574,7 +1613,8 @@ impl<'o, 'gcx: 'tcx, 'tcx> AstConv<'gcx, 'tcx>+'o { opt_self_ty: Option>, base_path_ref_id: ast::NodeId, base_segments: &[hir::PathSegment], - assoc_segments: &[hir::PathSegment]) + assoc_segments: &[hir::PathSegment], + permit_variants: bool) -> (Ty<'tcx>, Def) { // Convert the base type. debug!("finish_resolving_def_to_ty(base_def={:?}, \ @@ -1589,7 +1629,8 @@ impl<'o, 'gcx: 'tcx, 'tcx> AstConv<'gcx, 'tcx>+'o { base_def, opt_self_ty, base_path_ref_id, - base_segments); + base_segments, + permit_variants); debug!("finish_resolving_def_to_ty: base_def_to_ty returned {:?}", base_ty); // If any associated type segments remain, attempt to resolve them. @@ -1617,13 +1658,12 @@ impl<'o, 'gcx: 'tcx, 'tcx> AstConv<'gcx, 'tcx>+'o { let tcx = self.tcx(); let cache = self.ast_ty_to_ty_cache(); - match cache.borrow().get(&ast_ty.id) { - Some(ty) => { return ty; } - None => { } + if let Some(ty) = cache.borrow().get(&ast_ty.id) { + return ty; } let result_ty = match ast_ty.node { - hir::TyVec(ref ty) => { + hir::TySlice(ref ty) => { tcx.mk_slice(self.ast_ty_to_ty(rscope, &ty)) } hir::TyObjectSum(ref ty, ref bounds) => { @@ -1649,10 +1689,7 @@ impl<'o, 'gcx: 'tcx, 'tcx> AstConv<'gcx, 'tcx>+'o { tcx.types.never }, hir::TyTup(ref fields) => { - let flds = fields.iter() - .map(|t| self.ast_ty_to_ty(rscope, &t)) - .collect(); - tcx.mk_tup(flds) + tcx.mk_tup(fields.iter().map(|t| self.ast_ty_to_ty(rscope, &t))) } hir::TyBareFn(ref bf) => { require_c_abi_if_variadic(tcx, &bf.decl, bf.abi, ast_ty.span); @@ -1749,7 +1786,8 @@ impl<'o, 'gcx: 'tcx, 'tcx> AstConv<'gcx, 'tcx>+'o { opt_self_ty, ast_ty.id, &path.segments[..base_ty_end], - &path.segments[base_ty_end..]); + &path.segments[base_ty_end..], + false); // Write back the new resolution. if path_res.depth != 0 { @@ -1758,7 +1796,7 @@ impl<'o, 'gcx: 'tcx, 'tcx> AstConv<'gcx, 'tcx>+'o { ty } - hir::TyFixedLengthVec(ref ty, ref e) => { + hir::TyArray(ref ty, ref e) => { if let Ok(length) = eval_length(tcx.global_tcx(), &e, "array length") { tcx.mk_array(self.ast_ty_to_ty(rscope, &ty), length) } else { @@ -1859,15 +1897,22 @@ impl<'o, 'gcx: 'tcx, 'tcx> AstConv<'gcx, 'tcx>+'o { }; let arg_tys: Vec = arg_params.iter().map(|a| self.ty_of_arg(&rb, a, None)).collect(); - let arg_pats: Vec = - arg_params.iter().map(|a| pprust::pat_to_string(&a.pat)).collect(); // Second, if there was exactly one lifetime (either a substitution or a // reference) in the arguments, then any anonymous regions in the output // have that lifetime. let implied_output_region = match explicit_self_category { ty::ExplicitSelfCategory::ByReference(region, _) => Ok(*region), - _ => self.find_implied_output_region(&arg_tys, arg_pats) + _ => { + // `pat_to_string` is expensive and + // `find_implied_output_region` only needs its result when + // there's an error. So we wrap it in a closure to avoid + // calling it until necessary. + let arg_pats = || { + arg_params.iter().map(|a| pprust::pat_to_string(&a.pat)).collect() + }; + self.find_implied_output_region(&arg_tys, arg_pats) + } }; let output_ty = match decl.output { @@ -2199,10 +2244,12 @@ fn check_type_argument_count(tcx: TyCtxt, span: Span, supplied: usize, } else { "expected" }; + let arguments_plural = if required == 1 { "" } else { "s" }; struct_span_err!(tcx.sess, span, E0243, "wrong number of type arguments") .span_label( span, - &format!("{} {} type arguments, found {}", expected, required, supplied) + &format!("{} {} type argument{}, found {}", + expected, required, arguments_plural, supplied) ) .emit(); } else if supplied > accepted { @@ -2213,11 +2260,12 @@ fn check_type_argument_count(tcx: TyCtxt, span: Span, supplied: usize, } else { format!("expected {}", accepted) }; + let arguments_plural = if accepted == 1 { "" } else { "s" }; struct_span_err!(tcx.sess, span, E0244, "wrong number of type arguments") .span_label( span, - &format!("{} type arguments, found {}", expected, supplied) + &format!("{} type argument{}, found {}", expected, arguments_plural, supplied) ) .emit(); } diff --git a/src/librustc_typeck/check/_match.rs b/src/librustc_typeck/check/_match.rs index 507de9a9e3..c842514227 100644 --- a/src/librustc_typeck/check/_match.rs +++ b/src/librustc_typeck/check/_match.rs @@ -8,12 +8,12 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -use hir::def::Def; +use rustc::hir::{self, PatKind}; +use rustc::hir::def::{Def, CtorKind}; +use rustc::hir::pat_util::EnumerateAndAdjustIterator; use rustc::infer::{self, InferOk, TypeOrigin}; -use hir::pat_util::EnumerateAndAdjustIterator; -use rustc::ty::{self, Ty, TypeFoldable, LvaluePreference, VariantKind}; +use rustc::ty::{self, Ty, TypeFoldable, LvaluePreference}; use check::{FnCtxt, Expectation}; -use lint; use util::nodemap::FnvHashMap; use std::collections::hash_map::Entry::{Occupied, Vacant}; @@ -23,9 +23,6 @@ use syntax::codemap::Spanned; use syntax::ptr::P; use syntax_pos::Span; -use rustc::hir::{self, PatKind}; -use rustc::hir::print as pprust; - impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { pub fn check_pat(&self, pat: &'gcx hir::Pat, expected: Ty<'tcx>) { let tcx = self.tcx; @@ -171,8 +168,9 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { } let max_len = cmp::max(expected_len, elements.len()); - let element_tys: Vec<_> = (0 .. max_len).map(|_| self.next_ty_var()).collect(); - let pat_ty = tcx.mk_tup(element_tys.clone()); + let element_tys_iter = (0..max_len).map(|_| self.next_ty_var()); + let element_tys = tcx.mk_type_list(element_tys_iter); + let pat_ty = tcx.mk_ty(ty::TyTuple(element_tys)); self.demand_eqtype(pat.span, expected, pat_ty); for (i, elem) in elements.iter().enumerate_and_adjust(max_len, ddpos) { self.check_pat(elem, &element_tys[i]); @@ -227,7 +225,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { tcx.types.err } } - PatKind::Vec(ref before, ref slice, ref after) => { + PatKind::Slice(ref before, ref slice, ref after) => { let expected_ty = self.structurally_resolved_type(pat.span, expected); let (inner_ty, slice_ty) = match expected_ty.sty { ty::TyArray(inner_ty, size) => { @@ -491,8 +489,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { expected: Ty<'tcx>) -> Ty<'tcx> { // Resolve the path and check the definition for errors. - let (variant, pat_ty) = if let Some(variant_ty) = self.check_struct_path(path, pat.id, - pat.span) { + let (variant, pat_ty) = if let Some(variant_ty) = self.check_struct_path(path, pat.id) { variant_ty } else { for field in fields { @@ -516,10 +513,10 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { expected: Ty<'tcx>) -> Ty<'tcx> { let tcx = self.tcx; - let report_unexpected_def = || { + let report_unexpected_def = |def: Def| { span_err!(tcx.sess, pat.span, E0533, - "`{}` does not name a unit variant, unit struct or a constant", - pprust::path_to_string(path)); + "expected unit struct/variant or constant, found {} `{}`", + def.kind_name(), path); }; // Resolve the path and check the definition for errors. @@ -531,26 +528,13 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { return tcx.types.err; } Def::Method(..) => { - report_unexpected_def(); + report_unexpected_def(def); return tcx.types.err; } - Def::Variant(..) => { - let variant = tcx.expect_variant_def(def); - if variant.kind != VariantKind::Unit { - report_unexpected_def(); - return tcx.types.err; - } - } - Def::Struct(ctor_did) => { - let did = tcx.parent_def_id(ctor_did).expect("struct ctor has no parent"); - let variant = tcx.lookup_adt_def(did).struct_variant(); - if variant.kind != VariantKind::Unit { - report_unexpected_def(); - return tcx.types.err; - } - } + Def::VariantCtor(_, CtorKind::Const) | + Def::StructCtor(_, CtorKind::Const) | Def::Const(..) | Def::AssociatedConst(..) => {} // OK - _ => bug!("unexpected pattern definition {:?}", def) + _ => bug!("unexpected pattern definition: {:?}", def) } // Type check the path. @@ -572,17 +556,12 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { self.check_pat(&pat, tcx.types.err); } }; - let report_unexpected_def = |is_lint| { - let msg = format!("`{}` does not name a tuple variant or a tuple struct", - pprust::path_to_string(path)); - if is_lint { - tcx.sess.add_lint(lint::builtin::MATCH_OF_UNIT_VARIANT_VIA_PAREN_DOTDOT, - pat.id, pat.span, msg); - } else { - struct_span_err!(tcx.sess, pat.span, E0164, "{}", msg) - .span_label(pat.span, &format!("not a tuple variant or struct")).emit(); - on_error(); - } + let report_unexpected_def = |def: Def| { + let msg = format!("expected tuple struct/variant, found {} `{}`", + def.kind_name(), path); + struct_span_err!(tcx.sess, pat.span, E0164, "{}", msg) + .span_label(pat.span, &format!("not a tuple variant or struct")).emit(); + on_error(); }; // Resolve the path and check the definition for errors. @@ -593,37 +572,21 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { on_error(); return tcx.types.err; } - Def::Const(..) | Def::AssociatedConst(..) | Def::Method(..) => { - report_unexpected_def(false); + Def::AssociatedConst(..) | Def::Method(..) => { + report_unexpected_def(def); return tcx.types.err; } - Def::Variant(..) => { + Def::VariantCtor(_, CtorKind::Fn) | + Def::StructCtor(_, CtorKind::Fn) => { tcx.expect_variant_def(def) } - Def::Struct(ctor_did) => { - let did = tcx.parent_def_id(ctor_did).expect("struct ctor has no parent"); - tcx.lookup_adt_def(did).struct_variant() - } - _ => bug!("unexpected pattern definition {:?}", def) + _ => bug!("unexpected pattern definition: {:?}", def) }; - if variant.kind == VariantKind::Unit && subpats.is_empty() && ddpos.is_some() { - // Matching unit structs with tuple variant patterns (`UnitVariant(..)`) - // is allowed for backward compatibility. - report_unexpected_def(true); - } else if variant.kind != VariantKind::Tuple { - report_unexpected_def(false); - return tcx.types.err; - } // Type check the path. let pat_ty = self.instantiate_value_path(segments, opt_ty, def, pat.span, pat.id); - let pat_ty = if pat_ty.is_fn() { - // Replace constructor type with constructed type for tuple struct patterns. - tcx.no_late_bound_regions(&pat_ty.fn_ret()).unwrap() - } else { - // Leave the type as is for unit structs (backward compatibility). - pat_ty - }; + // Replace constructor type with constructed type for tuple struct patterns. + let pat_ty = tcx.no_late_bound_regions(&pat_ty.fn_ret()).expect("expected fn type"); self.demand_eqtype(pat.span, expected, pat_ty); // Type check subpatterns. @@ -638,16 +601,8 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { self.check_pat(&subpat, field_ty); } } else { - let subpats_ending = if subpats.len() == 1 { - "" - } else { - "s" - }; - let fields_ending = if variant.fields.len() == 1 { - "" - } else { - "s" - }; + let subpats_ending = if subpats.len() == 1 { "" } else { "s" }; + let fields_ending = if variant.fields.len() == 1 { "" } else { "s" }; struct_span_err!(tcx.sess, pat.span, E0023, "this pattern has {} field{}, but the corresponding {} has {} field{}", subpats.len(), subpats_ending, def.kind_name(), @@ -687,14 +642,14 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { for &Spanned { node: ref field, span } in fields { let field_ty = match used_fields.entry(field.name) { Occupied(occupied) => { - let mut err = struct_span_err!(tcx.sess, span, E0025, - "field `{}` bound multiple times \ - in the pattern", - field.name); - span_note!(&mut err, *occupied.get(), - "field `{}` previously bound here", - field.name); - err.emit(); + struct_span_err!(tcx.sess, span, E0025, + "field `{}` bound multiple times \ + in the pattern", + field.name) + .span_label(span, + &format!("multiple uses of `{}` in pattern", field.name)) + .span_label(*occupied.get(), &format!("first use of `{}`", field.name)) + .emit(); tcx.types.err } Vacant(vacant) => { diff --git a/src/librustc_typeck/check/assoc.rs b/src/librustc_typeck/check/assoc.rs index 41f34b9040..9610477d8f 100644 --- a/src/librustc_typeck/check/assoc.rs +++ b/src/librustc_typeck/check/assoc.rs @@ -9,13 +9,13 @@ // except according to those terms. use rustc::infer::InferCtxt; -use rustc::traits::{self, FulfillmentContext, Normalized, MiscObligation, - SelectionContext, ObligationCause}; +use rustc::traits::{self, FulfillmentContext, Normalized, MiscObligation, SelectionContext, + ObligationCause}; use rustc::ty::fold::TypeFoldable; use syntax::ast; use syntax_pos::Span; -//FIXME(@jroesch): Ideally we should be able to drop the fulfillment_cx argument. +// FIXME(@jroesch): Ideally we should be able to drop the fulfillment_cx argument. pub fn normalize_associated_types_in<'a, 'gcx, 'tcx, T>( infcx: &InferCtxt<'a, 'gcx, 'tcx>, fulfillment_cx: &mut FulfillmentContext<'tcx>, diff --git a/src/librustc_typeck/check/autoderef.rs b/src/librustc_typeck/check/autoderef.rs index 19261a2447..900c22a817 100644 --- a/src/librustc_typeck/check/autoderef.rs +++ b/src/librustc_typeck/check/autoderef.rs @@ -16,7 +16,6 @@ use rustc::traits; use rustc::ty::{self, Ty, TraitRef}; use rustc::ty::{ToPredicate, TypeFoldable}; use rustc::ty::{MethodCall, MethodCallee}; -use rustc::ty::subst::Substs; use rustc::ty::{LvaluePreference, NoPreference, PreferMutLvalue}; use rustc::hir; @@ -26,7 +25,7 @@ use syntax::parse::token; #[derive(Copy, Clone, Debug)] enum AutoderefKind { Builtin, - Overloaded + Overloaded, } pub struct Autoderef<'a, 'gcx: 'tcx, 'tcx: 'a> { @@ -35,7 +34,7 @@ pub struct Autoderef<'a, 'gcx: 'tcx, 'tcx: 'a> { cur_ty: Ty<'tcx>, obligations: Vec>, at_start: bool, - span: Span + span: Span, } impl<'a, 'gcx, 'tcx> Iterator for Autoderef<'a, 'gcx, 'tcx> { @@ -45,7 +44,8 @@ impl<'a, 'gcx, 'tcx> Iterator for Autoderef<'a, 'gcx, 'tcx> { let tcx = self.fcx.tcx; debug!("autoderef: steps={:?}, cur_ty={:?}", - self.steps, self.cur_ty); + self.steps, + self.cur_ty); if self.at_start { self.at_start = false; debug!("autoderef stage #0 is {:?}", self.cur_ty); @@ -54,11 +54,13 @@ impl<'a, 'gcx, 'tcx> Iterator for Autoderef<'a, 'gcx, 'tcx> { if self.steps.len() == tcx.sess.recursion_limit.get() { // We've reached the recursion limit, error gracefully. - struct_span_err!(tcx.sess, self.span, E0055, - "reached the recursion limit while auto-dereferencing {:?}", - self.cur_ty) - .span_label(self.span, &format!("deref recursion limit reached")) - .emit(); + struct_span_err!(tcx.sess, + self.span, + E0055, + "reached the recursion limit while auto-dereferencing {:?}", + self.cur_ty) + .span_label(self.span, &format!("deref recursion limit reached")) + .emit(); return None; } @@ -72,7 +74,7 @@ impl<'a, 'gcx, 'tcx> Iterator for Autoderef<'a, 'gcx, 'tcx> { } else { match self.overloaded_deref_ty(self.cur_ty) { Some(ty) => (AutoderefKind::Overloaded, ty), - _ => return None + _ => return None, } }; @@ -81,8 +83,10 @@ impl<'a, 'gcx, 'tcx> Iterator for Autoderef<'a, 'gcx, 'tcx> { } self.steps.push((self.cur_ty, kind)); - debug!("autoderef stage #{:?} is {:?} from {:?}", self.steps.len(), - new_ty, (self.cur_ty, kind)); + debug!("autoderef stage #{:?} is {:?} from {:?}", + self.steps.len(), + new_ty, + (self.cur_ty, kind)); self.cur_ty = new_ty; Some((self.cur_ty, self.steps.len())) @@ -99,9 +103,9 @@ impl<'a, 'gcx, 'tcx> Autoderef<'a, 'gcx, 'tcx> { let trait_ref = TraitRef { def_id: match tcx.lang_items.deref_trait() { Some(f) => f, - None => return None + None => return None, }, - substs: Substs::new_trait(tcx, self.cur_ty, &[]) + substs: tcx.mk_substs_trait(self.cur_ty, &[]), }; let cause = traits::ObligationCause::misc(self.span, self.fcx.body_id); @@ -113,15 +117,13 @@ impl<'a, 'gcx, 'tcx> Autoderef<'a, 'gcx, 'tcx> { return None; } - let normalized = traits::normalize_projection_type( - &mut selcx, - ty::ProjectionTy { - trait_ref: trait_ref, - item_name: token::intern("Target") - }, - cause, - 0 - ); + let normalized = traits::normalize_projection_type(&mut selcx, + ty::ProjectionTy { + trait_ref: trait_ref, + item_name: token::intern("Target"), + }, + cause, + 0); debug!("overloaded_deref_ty({:?}) = {:?}", ty, normalized); self.obligations.extend(normalized.obligations); @@ -134,17 +136,23 @@ impl<'a, 'gcx, 'tcx> Autoderef<'a, 'gcx, 'tcx> { } pub fn finalize<'b, I>(self, pref: LvaluePreference, exprs: I) - where I: IntoIterator + where I: IntoIterator { - let methods : Vec<_> = self.steps.iter().map(|&(ty, kind)| { - if let AutoderefKind::Overloaded = kind { - self.fcx.try_overloaded_deref(self.span, None, ty, pref) - } else { - None - } - }).collect(); + let methods: Vec<_> = self.steps + .iter() + .map(|&(ty, kind)| { + if let AutoderefKind::Overloaded = kind { + self.fcx.try_overloaded_deref(self.span, None, ty, pref) + } else { + None + } + }) + .collect(); - debug!("finalize({:?}) - {:?},{:?}", pref, methods, self.obligations); + debug!("finalize({:?}) - {:?},{:?}", + pref, + methods, + self.obligations); for expr in exprs { debug!("finalize - finalizing #{} - {:?}", expr.id, expr); @@ -163,18 +171,14 @@ impl<'a, 'gcx, 'tcx> Autoderef<'a, 'gcx, 'tcx> { } impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { - pub fn autoderef(&'a self, - span: Span, - base_ty: Ty<'tcx>) - -> Autoderef<'a, 'gcx, 'tcx> - { + pub fn autoderef(&'a self, span: Span, base_ty: Ty<'tcx>) -> Autoderef<'a, 'gcx, 'tcx> { Autoderef { fcx: self, steps: vec![], cur_ty: self.resolve_type_vars_if_possible(&base_ty), obligations: vec![], at_start: true, - span: span + span: span, } } @@ -183,28 +187,36 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { base_expr: Option<&hir::Expr>, base_ty: Ty<'tcx>, lvalue_pref: LvaluePreference) - -> Option> - { + -> Option> { debug!("try_overloaded_deref({:?},{:?},{:?},{:?})", - span, base_expr, base_ty, lvalue_pref); + span, + base_expr, + base_ty, + lvalue_pref); // Try DerefMut first, if preferred. let method = match (lvalue_pref, self.tcx.lang_items.deref_mut_trait()) { (PreferMutLvalue, Some(trait_did)) => { - self.lookup_method_in_trait(span, base_expr, - token::intern("deref_mut"), trait_did, - base_ty, None) + self.lookup_method_in_trait(span, + base_expr, + token::intern("deref_mut"), + trait_did, + base_ty, + None) } - _ => None + _ => None, }; // Otherwise, fall back to Deref. let method = match (method, self.tcx.lang_items.deref_trait()) { (None, Some(trait_did)) => { - self.lookup_method_in_trait(span, base_expr, - token::intern("deref"), trait_did, - base_ty, None) + self.lookup_method_in_trait(span, + base_expr, + token::intern("deref"), + trait_did, + base_ty, + None) } - (method, _) => method + (method, _) => method, }; method diff --git a/src/librustc_typeck/check/callee.rs b/src/librustc_typeck/check/callee.rs index d1fb0736d2..3cf64fa439 100644 --- a/src/librustc_typeck/check/callee.rs +++ b/src/librustc_typeck/check/callee.rs @@ -8,8 +8,7 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -use super::{DeferredCallResolution, Expectation, FnCtxt, - TupleArgumentsFlag}; +use super::{DeferredCallResolution, Expectation, FnCtxt, TupleArgumentsFlag}; use CrateCtxt; use hir::def::Def; @@ -27,7 +26,10 @@ use rustc::hir; /// method that is called) pub fn check_legal_trait_for_method_call(ccx: &CrateCtxt, span: Span, trait_id: DefId) { if ccx.tcx.lang_items.drop_trait() == Some(trait_id) { - struct_span_err!(ccx.tcx.sess, span, E0040, "explicit use of destructor method") + struct_span_err!(ccx.tcx.sess, + span, + E0040, + "explicit use of destructor method") .span_label(span, &format!("explicit destructor calls not allowed")) .emit(); } @@ -36,7 +38,7 @@ pub fn check_legal_trait_for_method_call(ccx: &CrateCtxt, span: Span, trait_id: enum CallStep<'tcx> { Builtin, DeferredClosure(ty::FnSig<'tcx>), - Overloaded(ty::MethodCallee<'tcx>) + Overloaded(ty::MethodCallee<'tcx>), } impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { @@ -44,14 +46,17 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { call_expr: &'gcx hir::Expr, callee_expr: &'gcx hir::Expr, arg_exprs: &'gcx [P], - expected: Expectation<'tcx>) -> Ty<'tcx> - { + expected: Expectation<'tcx>) + -> Ty<'tcx> { let original_callee_ty = self.check_expr(callee_expr); - - let mut autoderef = self.autoderef(callee_expr.span, original_callee_ty); - let result = autoderef.by_ref().flat_map(|(adj_ty, idx)| { - self.try_overloaded_call_step(call_expr, callee_expr, adj_ty, idx) - }).next(); + let expr_ty = self.structurally_resolved_type(call_expr.span, original_callee_ty); + + let mut autoderef = self.autoderef(callee_expr.span, expr_ty); + let result = autoderef.by_ref() + .flat_map(|(adj_ty, idx)| { + self.try_overloaded_call_step(call_expr, callee_expr, adj_ty, idx) + }) + .next(); let callee_ty = autoderef.unambiguous_final_ty(); autoderef.finalize(LvaluePreference::NoPreference, Some(callee_expr)); @@ -70,8 +75,11 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { } Some(CallStep::Overloaded(method_callee)) => { - self.confirm_overloaded_call(call_expr, callee_expr, - arg_exprs, expected, method_callee) + self.confirm_overloaded_call(call_expr, + callee_expr, + arg_exprs, + expected, + method_callee) } }; @@ -86,8 +94,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { callee_expr: &'gcx hir::Expr, adjusted_ty: Ty<'tcx>, autoderefs: usize) - -> Option> - { + -> Option> { debug!("try_overloaded_call_step(call_expr={:?}, adjusted_ty={:?}, autoderefs={})", call_expr, adjusted_ty, @@ -96,7 +103,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { // If the callee is a bare function or a closure, then we're all set. match self.structurally_resolved_type(callee_expr.span, adjusted_ty).sty { ty::TyFnDef(..) | ty::TyFnPtr(_) => { - self.write_autoderef_adjustment(callee_expr.id, autoderefs); + self.write_autoderef_adjustment(callee_expr.id, autoderefs, adjusted_ty); return Some(CallStep::Builtin); } @@ -107,20 +114,20 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { // haven't yet decided on whether the closure is fn vs // fnmut vs fnonce. If so, we have to defer further processing. if self.closure_kind(def_id).is_none() { - let closure_ty = - self.closure_type(def_id, substs); - let fn_sig = - self.replace_late_bound_regions_with_fresh_var(call_expr.span, - infer::FnCall, - &closure_ty.sig).0; - self.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 - })); + let closure_ty = self.closure_type(def_id, substs); + let fn_sig = self.replace_late_bound_regions_with_fresh_var(call_expr.span, + infer::FnCall, + &closure_ty.sig) + .0; + self.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)); } } @@ -149,14 +156,12 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { callee_expr: &hir::Expr, adjusted_ty: Ty<'tcx>, autoderefs: usize) - -> Option> - { + -> Option> { // Try the options that are least restrictive on the caller first. - for &(opt_trait_def_id, method_name) in &[ - (self.tcx.lang_items.fn_trait(), token::intern("call")), - (self.tcx.lang_items.fn_mut_trait(), token::intern("call_mut")), - (self.tcx.lang_items.fn_once_trait(), token::intern("call_once")), - ] { + for &(opt_trait_def_id, method_name) in + &[(self.tcx.lang_items.fn_trait(), token::intern("call")), + (self.tcx.lang_items.fn_mut_trait(), token::intern("call_mut")), + (self.tcx.lang_items.fn_once_trait(), token::intern("call_once"))] { let trait_def_id = match opt_trait_def_id { Some(def_id) => def_id, None => continue, @@ -184,19 +189,20 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { call_expr: &hir::Expr, callee_ty: Ty<'tcx>, arg_exprs: &'gcx [P], - expected: Expectation<'tcx>) -> Ty<'tcx> - { + expected: Expectation<'tcx>) + -> Ty<'tcx> { let error_fn_sig; let fn_sig = match callee_ty.sty { - ty::TyFnDef(.., &ty::BareFnTy {ref sig, ..}) | - ty::TyFnPtr(&ty::BareFnTy {ref sig, ..}) => { - sig - } + ty::TyFnDef(.., &ty::BareFnTy { ref sig, .. }) | + ty::TyFnPtr(&ty::BareFnTy { ref sig, .. }) => sig, _ => { - let mut err = self.type_error_struct(call_expr.span, |actual| { - format!("expected function, found `{}`", actual) - }, callee_ty); + let mut err = self.type_error_struct(call_expr.span, + |actual| { + format!("expected function, found `{}`", + actual) + }, + callee_ty); if let hir::ExprCall(ref expr, _) = call_expr.node { let tcx = self.tcx; @@ -217,7 +223,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { error_fn_sig = ty::Binder(ty::FnSig { inputs: self.err_args(arg_exprs.len()), output: self.tcx.types.err, - variadic: false + variadic: false, }); &error_fn_sig @@ -230,17 +236,16 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { // previously appeared within a `Binder<>` and hence would not // have been normalized before. let fn_sig = - self.replace_late_bound_regions_with_fresh_var(call_expr.span, - infer::FnCall, - fn_sig).0; - let fn_sig = - self.normalize_associated_types_in(call_expr.span, &fn_sig); + self.replace_late_bound_regions_with_fresh_var(call_expr.span, infer::FnCall, fn_sig) + .0; + let fn_sig = self.normalize_associated_types_in(call_expr.span, &fn_sig); // Call the generic checker. - let expected_arg_tys = self.expected_types_for_fn_args(call_expr.span, - expected, - fn_sig.output, - &fn_sig.inputs); + let expected_arg_tys = + self.expected_types_for_fn_args(call_expr.span, + expected, + fn_sig.output, + &fn_sig.inputs); self.check_argument_types(call_expr.span, &fn_sig.inputs, &expected_arg_tys[..], @@ -255,18 +260,17 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { call_expr: &hir::Expr, arg_exprs: &'gcx [P], expected: Expectation<'tcx>, - fn_sig: ty::FnSig<'tcx>) -> Ty<'tcx> - { + fn_sig: ty::FnSig<'tcx>) + -> Ty<'tcx> { // `fn_sig` is the *signature* of the cosure being called. We // don't know the full details yet (`Fn` vs `FnMut` etc), but we // do know the types expected for each argument and the return // type. - let expected_arg_tys = - self.expected_types_for_fn_args(call_expr.span, - expected, - fn_sig.output.clone(), - &fn_sig.inputs); + let expected_arg_tys = self.expected_types_for_fn_args(call_expr.span, + expected, + fn_sig.output.clone(), + &fn_sig.inputs); self.check_argument_types(call_expr.span, &fn_sig.inputs, @@ -283,15 +287,14 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { callee_expr: &'gcx hir::Expr, arg_exprs: &'gcx [P], expected: Expectation<'tcx>, - method_callee: ty::MethodCallee<'tcx>) -> Ty<'tcx> - { - let output_type = - self.check_method_argument_types(call_expr.span, - method_callee.ty, - callee_expr, - arg_exprs, - TupleArgumentsFlag::TupleArguments, - expected); + method_callee: ty::MethodCallee<'tcx>) + -> Ty<'tcx> { + let output_type = self.check_method_argument_types(call_expr.span, + method_callee.ty, + callee_expr, + arg_exprs, + TupleArgumentsFlag::TupleArguments, + expected); self.write_overloaded_call_method_map(call_expr, method_callee); output_type @@ -317,16 +320,17 @@ struct CallResolution<'gcx: 'tcx, 'tcx> { impl<'gcx, 'tcx> DeferredCallResolution<'gcx, 'tcx> for CallResolution<'gcx, 'tcx> { fn resolve<'a>(&mut self, fcx: &FnCtxt<'a, 'gcx, 'tcx>) { - debug!("DeferredCallResolution::resolve() {:?}", - self); + debug!("DeferredCallResolution::resolve() {:?}", self); // we should not be invoked until the closure kind has been // determined by upvar inference assert!(fcx.closure_kind(self.closure_def_id).is_some()); // We may now know enough to figure out fn vs fnmut etc. - match fcx.try_overloaded_call_traits(self.call_expr, self.callee_expr, - self.adjusted_ty, self.autoderefs) { + match fcx.try_overloaded_call_traits(self.call_expr, + self.callee_expr, + 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 @@ -336,28 +340,24 @@ impl<'gcx, 'tcx> DeferredCallResolution<'gcx, 'tcx> for CallResolution<'gcx, 'tc // can't because of the annoying need for a TypeTrace. // (This always bites me, should find a way to // refactor it.) - let method_sig = fcx.tcx.no_late_bound_regions(method_callee.ty.fn_sig()) - .unwrap(); + let method_sig = fcx.tcx + .no_late_bound_regions(method_callee.ty.fn_sig()) + .unwrap(); - debug!("attempt_resolution: method_callee={:?}", - method_callee); + debug!("attempt_resolution: method_callee={:?}", method_callee); for (&method_arg_ty, &self_arg_ty) in - method_sig.inputs[1..].iter().zip(&self.fn_sig.inputs) - { + method_sig.inputs[1..].iter().zip(&self.fn_sig.inputs) { fcx.demand_eqtype(self.call_expr.span, self_arg_ty, method_arg_ty); } - fcx.demand_eqtype(self.call_expr.span, - method_sig.output, - self.fn_sig.output); + fcx.demand_eqtype(self.call_expr.span, method_sig.output, self.fn_sig.output); fcx.write_overloaded_call_method_map(self.call_expr, method_callee); } None => { - span_bug!( - self.call_expr.span, - "failed to find an overloaded call trait for closure call"); + span_bug!(self.call_expr.span, + "failed to find an overloaded call trait for closure call"); } } } diff --git a/src/librustc_typeck/check/cast.rs b/src/librustc_typeck/check/cast.rs index 51a9b18392..c456b9358b 100644 --- a/src/librustc_typeck/check/cast.rs +++ b/src/librustc_typeck/check/cast.rs @@ -69,7 +69,7 @@ enum UnsizeKind<'tcx> { /// The unsize info of this projection OfProjection(&'tcx ty::ProjectionTy<'tcx>), /// The unsize info of this parameter - OfParam(&'tcx ty::ParamTy) + OfParam(&'tcx ty::ParamTy), } impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { @@ -83,13 +83,13 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { // FIXME(arielb1): do some kind of normalization match def.struct_variant().fields.last() { None => None, - Some(f) => self.unsize_kind(f.ty(self.tcx, substs)) + Some(f) => self.unsize_kind(f.ty(self.tcx, substs)), } } // We should really try to normalize here. ty::TyProjection(ref pi) => Some(UnsizeKind::OfProjection(pi)), ty::TyParam(ref p) => Some(UnsizeKind::OfParam(p)), - _ => None + _ => None, } } } @@ -133,9 +133,7 @@ impl<'a, 'gcx, 'tcx> CastCheck<'tcx> { check.report_cast_to_unsized_type(fcx); Err(ErrorReported) } - _ => { - Ok(check) - } + _ => Ok(check), } } @@ -145,18 +143,21 @@ impl<'a, 'gcx, 'tcx> CastCheck<'tcx> { CastError::NeedViaThinPtr | CastError::NeedViaInt | CastError::NeedViaUsize => { - fcx.type_error_struct(self.span, |actual| { - format!("casting `{}` as `{}` is invalid", - actual, - fcx.ty_to_string(self.cast_ty)) - }, self.expr_ty) - .help(&format!("cast through {} first", match e { - CastError::NeedViaPtr => "a raw pointer", - CastError::NeedViaThinPtr => "a thin pointer", - CastError::NeedViaInt => "an integer", - CastError::NeedViaUsize => "a usize", - _ => bug!() - })) + fcx.type_error_struct(self.span, + |actual| { + format!("casting `{}` as `{}` is invalid", + actual, + fcx.ty_to_string(self.cast_ty)) + }, + self.expr_ty) + .help(&format!("cast through {} first", + match e { + CastError::NeedViaPtr => "a raw pointer", + CastError::NeedViaThinPtr => "a thin pointer", + CastError::NeedViaInt => "an integer", + CastError::NeedViaUsize => "a usize", + _ => bug!(), + })) .emit(); } CastError::CastToBool => { @@ -166,37 +167,49 @@ impl<'a, 'gcx, 'tcx> CastCheck<'tcx> { .emit(); } CastError::CastToChar => { - fcx.type_error_message(self.span, |actual| { - format!("only `u8` can be cast as `char`, not `{}`", actual) - }, self.expr_ty); + fcx.type_error_message(self.span, + |actual| { + format!("only `u8` can be cast as `char`, not `{}`", + actual) + }, + self.expr_ty); } CastError::NonScalar => { - fcx.type_error_message(self.span, |actual| { - format!("non-scalar cast: `{}` as `{}`", - actual, - fcx.ty_to_string(self.cast_ty)) - }, self.expr_ty); + fcx.type_error_message(self.span, + |actual| { + format!("non-scalar cast: `{}` as `{}`", + actual, + fcx.ty_to_string(self.cast_ty)) + }, + self.expr_ty); } CastError::IllegalCast => { - fcx.type_error_message(self.span, |actual| { - format!("casting `{}` as `{}` is invalid", - actual, - fcx.ty_to_string(self.cast_ty)) - }, self.expr_ty); + fcx.type_error_message(self.span, + |actual| { + format!("casting `{}` as `{}` is invalid", + actual, + fcx.ty_to_string(self.cast_ty)) + }, + self.expr_ty); } CastError::SizedUnsizedCast => { - fcx.type_error_message(self.span, |actual| { - format!("cannot cast thin pointer `{}` to fat pointer `{}`", - actual, - fcx.ty_to_string(self.cast_ty)) - }, self.expr_ty) + fcx.type_error_message(self.span, + |actual| { + format!("cannot cast thin pointer `{}` to fat pointer \ + `{}`", + actual, + fcx.ty_to_string(self.cast_ty)) + }, + self.expr_ty) } CastError::DifferingKinds => { - fcx.type_error_struct(self.span, |actual| { - format!("casting `{}` as `{}` is invalid", - actual, - fcx.ty_to_string(self.cast_ty)) - }, self.expr_ty) + fcx.type_error_struct(self.span, + |actual| { + format!("casting `{}` as `{}` is invalid", + actual, + fcx.ty_to_string(self.cast_ty)) + }, + self.expr_ty) .note("vtable kinds may not match") .emit(); } @@ -204,22 +217,22 @@ impl<'a, 'gcx, 'tcx> CastCheck<'tcx> { } fn report_cast_to_unsized_type(&self, fcx: &FnCtxt<'a, 'gcx, 'tcx>) { - if - self.cast_ty.references_error() || - self.expr_ty.references_error() - { + if self.cast_ty.references_error() || self.expr_ty.references_error() { return; } let tstr = fcx.ty_to_string(self.cast_ty); - let mut err = fcx.type_error_struct(self.span, |actual| { - format!("cast to unsized type: `{}` as `{}`", actual, tstr) - }, self.expr_ty); + let mut err = + fcx.type_error_struct(self.span, + |actual| { + format!("cast to unsized type: `{}` as `{}`", actual, tstr) + }, + self.expr_ty); match self.expr_ty.sty { ty::TyRef(_, ty::TypeAndMut { mutbl: mt, .. }) => { let mtstr = match mt { hir::MutMutable => "mut ", - hir::MutImmutable => "" + hir::MutImmutable => "", }; if self.cast_ty.is_trait() { match fcx.tcx.sess.codemap().span_to_snippet(self.cast_span) { @@ -227,15 +240,17 @@ impl<'a, 'gcx, 'tcx> CastCheck<'tcx> { err.span_suggestion(self.cast_span, "try casting to a reference instead:", format!("&{}{}", mtstr, s)); - }, - Err(_) => - span_help!(err, self.cast_span, - "did you mean `&{}{}`?", mtstr, tstr), + } + Err(_) => { + span_help!(err, self.cast_span, "did you mean `&{}{}`?", mtstr, tstr) + } } } else { - span_help!(err, self.span, + span_help!(err, + self.span, "consider using an implicit coercion to `&{}{}` instead", - mtstr, tstr); + mtstr, + tstr); } } ty::TyBox(..) => { @@ -244,13 +259,13 @@ impl<'a, 'gcx, 'tcx> CastCheck<'tcx> { err.span_suggestion(self.cast_span, "try casting to a `Box` instead:", format!("Box<{}>", s)); - }, - Err(_) => - span_help!(err, self.cast_span, "did you mean `Box<{}>`?", tstr), + } + Err(_) => span_help!(err, self.cast_span, "did you mean `Box<{}>`?", tstr), } } _ => { - span_help!(err, self.expr.span, + span_help!(err, + self.expr.span, "consider using a box or reference as appropriate"); } } @@ -286,7 +301,9 @@ impl<'a, 'gcx, 'tcx> CastCheck<'tcx> { self.expr_ty = fcx.structurally_resolved_type(self.span, self.expr_ty); self.cast_ty = fcx.structurally_resolved_type(self.span, self.cast_ty); - debug!("check_cast({}, {:?} as {:?})", self.expr.id, self.expr_ty, + debug!("check_cast({}, {:?} as {:?})", + self.expr.id, + self.expr_ty, self.cast_ty); if !fcx.type_is_known_to_be_sized(self.cast_ty, self.span) { @@ -296,15 +313,16 @@ impl<'a, 'gcx, 'tcx> CastCheck<'tcx> { } else if self.try_coercion_cast(fcx) { self.trivial_cast_lint(fcx); debug!(" -> CoercionCast"); - fcx.tcx.cast_kinds.borrow_mut().insert(self.expr.id, - CastKind::CoercionCast); - } else { match self.do_check(fcx) { - Ok(k) => { - debug!(" -> {:?}", k); - fcx.tcx.cast_kinds.borrow_mut().insert(self.expr.id, k); - } - Err(e) => self.report_cast_error(fcx, e) - };} + fcx.tcx.cast_kinds.borrow_mut().insert(self.expr.id, CastKind::CoercionCast); + } else { + match self.do_check(fcx) { + Ok(k) => { + debug!(" -> {:?}", k); + fcx.tcx.cast_kinds.borrow_mut().insert(self.expr.id, k); + } + Err(e) => self.report_cast_error(fcx, e), + }; + } } /// Check a cast, and report an error if one exists. In some cases, this @@ -330,9 +348,7 @@ impl<'a, 'gcx, 'tcx> CastCheck<'tcx> { return Err(CastError::NonScalar); } } - _ => { - return Err(CastError::NonScalar) - } + _ => return Err(CastError::NonScalar), }; match (t_from, t_cast) { @@ -347,17 +363,20 @@ impl<'a, 'gcx, 'tcx> CastCheck<'tcx> { (_, Int(Char)) => Err(CastError::CastToChar), // prim -> float,ptr - (Int(Bool), Float) | (Int(CEnum), Float) | (Int(Char), Float) - => Err(CastError::NeedViaInt), - (Int(Bool), Ptr(_)) | (Int(CEnum), Ptr(_)) | (Int(Char), Ptr(_)) - => Err(CastError::NeedViaUsize), + (Int(Bool), Float) | + (Int(CEnum), Float) | + (Int(Char), Float) => Err(CastError::NeedViaInt), + (Int(Bool), Ptr(_)) | + (Int(CEnum), Ptr(_)) | + (Int(Char), Ptr(_)) => Err(CastError::NeedViaUsize), // ptr -> * (Ptr(m_e), Ptr(m_c)) => self.check_ptr_ptr_cast(fcx, m_e, m_c), // ptr-ptr-cast (Ptr(m_expr), Int(_)) => self.check_ptr_addr_cast(fcx, m_expr), // ptr-addr-cast (Ptr(_), Float) | (FnPtr, Float) => Err(CastError::NeedViaUsize), (FnPtr, Int(_)) => Ok(CastKind::FnPtrAddrCast), - (RPtr(_), Int(_)) | (RPtr(_), Float) => Err(CastError::NeedViaPtr), + (RPtr(_), Int(_)) | + (RPtr(_), Float) => Err(CastError::NeedViaPtr), // * -> ptr (Int(_), Ptr(mt)) => self.check_addr_ptr_cast(fcx, mt), // addr-ptr-cast (FnPtr, Ptr(mt)) => self.check_fptr_ptr_cast(fcx, mt), @@ -366,12 +385,12 @@ impl<'a, 'gcx, 'tcx> CastCheck<'tcx> { // prim -> prim (Int(CEnum), Int(_)) => Ok(CastKind::EnumCast), - (Int(Char), Int(_)) | (Int(Bool), Int(_)) => Ok(CastKind::PrimIntCast), + (Int(Char), Int(_)) | + (Int(Bool), Int(_)) => Ok(CastKind::PrimIntCast), - (Int(_), Int(_)) | - (Int(_), Float) | - (Float, Int(_)) | - (Float, Float) => Ok(CastKind::NumericCast), + (Int(_), Int(_)) | (Int(_), Float) | (Float, Int(_)) | (Float, Float) => { + Ok(CastKind::NumericCast) + } } } @@ -380,10 +399,8 @@ impl<'a, 'gcx, 'tcx> CastCheck<'tcx> { fcx: &FnCtxt<'a, 'gcx, 'tcx>, m_expr: &'tcx ty::TypeAndMut<'tcx>, m_cast: &'tcx ty::TypeAndMut<'tcx>) - -> Result - { - debug!("check_ptr_ptr_cast m_expr={:?} m_cast={:?}", - m_expr, m_cast); + -> Result { + debug!("check_ptr_ptr_cast m_expr={:?} m_cast={:?}", m_expr, m_cast); // ptr-ptr cast. vtables must match. // Cast to sized is OK @@ -399,15 +416,14 @@ impl<'a, 'gcx, 'tcx> CastCheck<'tcx> { // vtable kinds must match match (fcx.unsize_kind(m_cast.ty), fcx.unsize_kind(m_expr.ty)) { (Some(a), Some(b)) if a == b => Ok(CastKind::PtrPtrCast), - _ => Err(CastError::DifferingKinds) + _ => Err(CastError::DifferingKinds), } } fn check_fptr_ptr_cast(&self, fcx: &FnCtxt<'a, 'gcx, 'tcx>, m_cast: &'tcx ty::TypeAndMut<'tcx>) - -> Result - { + -> Result { // fptr-ptr cast. must be to sized ptr if fcx.type_is_known_to_be_sized(m_cast.ty, self.span) { @@ -420,8 +436,7 @@ impl<'a, 'gcx, 'tcx> CastCheck<'tcx> { fn check_ptr_addr_cast(&self, fcx: &FnCtxt<'a, 'gcx, 'tcx>, m_expr: &'tcx ty::TypeAndMut<'tcx>) - -> Result - { + -> Result { // ptr-addr cast. must be from sized ptr if fcx.type_is_known_to_be_sized(m_expr.ty, self.span) { @@ -435,8 +450,7 @@ impl<'a, 'gcx, 'tcx> CastCheck<'tcx> { fcx: &FnCtxt<'a, 'gcx, 'tcx>, m_expr: &'tcx ty::TypeAndMut<'tcx>, m_cast: &'tcx ty::TypeAndMut<'tcx>) - -> Result - { + -> Result { // array-ptr-cast. if m_expr.mutbl == hir::MutImmutable && m_cast.mutbl == hir::MutImmutable { @@ -460,28 +474,22 @@ impl<'a, 'gcx, 'tcx> CastCheck<'tcx> { fn check_addr_ptr_cast(&self, fcx: &FnCtxt<'a, 'gcx, 'tcx>, m_cast: &'tcx ty::TypeAndMut<'tcx>) - -> Result - { + -> Result { // ptr-addr cast. pointer must be thin. if fcx.type_is_known_to_be_sized(m_cast.ty, self.span) { - Ok(CastKind::AddrPtrCast) + Ok(CastKind::AddrPtrCast) } else { - Err(CastError::IllegalCast) + Err(CastError::IllegalCast) } } fn try_coercion_cast(&self, fcx: &FnCtxt<'a, 'gcx, 'tcx>) -> bool { fcx.try_coerce(self.expr, self.expr_ty, self.cast_ty).is_ok() } - } impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { - fn type_is_known_to_be_sized(&self, - ty: Ty<'tcx>, - span: Span) - -> bool - { + fn type_is_known_to_be_sized(&self, ty: Ty<'tcx>, span: Span) -> bool { traits::type_known_to_meet_builtin_bound(self, ty, ty::BoundSized, span) } } diff --git a/src/librustc_typeck/check/closure.rs b/src/librustc_typeck/check/closure.rs index 9e41d1b567..d478f1092b 100644 --- a/src/librustc_typeck/check/closure.rs +++ b/src/librustc_typeck/check/closure.rs @@ -24,7 +24,8 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { _capture: hir::CaptureClause, decl: &'gcx hir::FnDecl, body: &'gcx hir::Block, - expected: Expectation<'tcx>) -> Ty<'tcx> { + expected: Expectation<'tcx>) + -> Ty<'tcx> { debug!("check_expr_closure(expr={:?},expected={:?})", expr, expected); @@ -32,9 +33,9 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { // It's always helpful for inference if we know the kind of // closure sooner rather than later, so first examine the expected // type, and see if can glean a closure kind from there. - let (expected_sig,expected_kind) = match expected.to_option(self) { + let (expected_sig, expected_kind) = match expected.to_option(self) { Some(ty) => self.deduce_expectations_from_expected_type(ty), - None => (None, None) + None => (None, None), }; self.check_closure(expr, expected_kind, decl, body, expected_sig) } @@ -44,7 +45,8 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { opt_kind: Option, decl: &'gcx hir::FnDecl, body: &'gcx hir::Block, - expected_sig: Option>) -> Ty<'tcx> { + expected_sig: Option>) + -> Ty<'tcx> { let expr_def_id = self.tcx.map.local_def_id(expr.id); debug!("check_closure opt_kind={:?} expected_sig={:?}", @@ -64,22 +66,29 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { let upvar_tys = self.next_ty_vars(num_upvars); debug!("check_closure: expr.id={:?} upvar_tys={:?}", - expr.id, upvar_tys); + expr.id, + upvar_tys); let closure_type = self.tcx.mk_closure(expr_def_id, - self.parameter_environment.free_substs, - upvar_tys); - - let fn_sig = self.tcx.liberate_late_bound_regions( - self.tcx.region_maps.call_site_extent(expr.id, body.id), &fn_ty.sig); - let fn_sig = - (**self).normalize_associated_types_in(body.span, body.id, &fn_sig); - - check_fn(self, hir::Unsafety::Normal, expr.id, &fn_sig, decl, expr.id, &body); + self.parameter_environment.free_substs, + &upvar_tys); + + let fn_sig = self.tcx + .liberate_late_bound_regions(self.tcx.region_maps.call_site_extent(expr.id, body.id), + &fn_ty.sig); + let fn_sig = (**self).normalize_associated_types_in(body.span, body.id, &fn_sig); + + check_fn(self, + hir::Unsafety::Normal, + expr.id, + &fn_sig, + decl, + expr.id, + &body); // Tuple up the arguments and insert the resulting function type into // the `closures` table. - fn_ty.sig.0.inputs = vec![self.tcx.mk_tup(fn_ty.sig.0.inputs)]; + fn_ty.sig.0.inputs = vec![self.tcx.intern_tup(&fn_ty.sig.0.inputs[..])]; debug!("closure for {:?} --> sig={:?} opt_kind={:?}", expr_def_id, @@ -88,46 +97,47 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { self.tables.borrow_mut().closure_tys.insert(expr_def_id, fn_ty); match opt_kind { - Some(kind) => { self.tables.borrow_mut().closure_kinds.insert(expr_def_id, kind); } - None => { } + Some(kind) => { + self.tables.borrow_mut().closure_kinds.insert(expr_def_id, kind); + } + None => {} } closure_type } - fn deduce_expectations_from_expected_type(&self, expected_ty: Ty<'tcx>) - -> (Option>,Option) - { + fn deduce_expectations_from_expected_type + (&self, + expected_ty: Ty<'tcx>) + -> (Option>, Option) { debug!("deduce_expectations_from_expected_type(expected_ty={:?})", expected_ty); match expected_ty.sty { ty::TyTrait(ref object_type) => { - let sig = object_type.projection_bounds.iter().filter_map(|pb| { - let pb = pb.with_self_ty(self.tcx, self.tcx.types.err); - self.deduce_sig_from_projection(&pb) - }).next(); + let sig = object_type.projection_bounds + .iter() + .filter_map(|pb| { + let pb = pb.with_self_ty(self.tcx, self.tcx.types.err); + self.deduce_sig_from_projection(&pb) + }) + .next(); let kind = self.tcx.lang_items.fn_trait_kind(object_type.principal.def_id()); (sig, kind) } - ty::TyInfer(ty::TyVar(vid)) => { - self.deduce_expectations_from_obligations(vid) - } - _ => { - (None, None) - } + ty::TyInfer(ty::TyVar(vid)) => self.deduce_expectations_from_obligations(vid), + _ => (None, None), } } - fn deduce_expectations_from_obligations(&self, expected_vid: ty::TyVid) - -> (Option>, Option) - { + fn deduce_expectations_from_obligations + (&self, + expected_vid: ty::TyVid) + -> (Option>, Option) { let fulfillment_cx = self.fulfillment_cx.borrow(); // Here `expected_ty` is known to be a type inference variable. - let expected_sig = - fulfillment_cx - .pending_obligations() + let expected_sig = fulfillment_cx.pending_obligations() .iter() .map(|obligation| &obligation.obligation) .filter_map(|obligation| { @@ -142,9 +152,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { self.self_type_matches_expected_vid(trait_ref, expected_vid) .and_then(|_| self.deduce_sig_from_projection(proj_predicate)) } - _ => { - None - } + _ => None, } }) .next(); @@ -153,9 +161,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { // infer the kind. This can occur if there is a trait-reference // like `F : Fn
`. Note that due to subtyping we could encounter // many viable options, so pick the most restrictive. - let expected_kind = - fulfillment_cx - .pending_obligations() + let expected_kind = fulfillment_cx.pending_obligations() .iter() .map(|obligation| &obligation.obligation) .filter_map(|obligation| { @@ -178,11 +184,11 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { // inference variable. ty::Predicate::ClosureKind(..) => None, }; - opt_trait_ref - .and_then(|tr| self.self_type_matches_expected_vid(tr, expected_vid)) + opt_trait_ref.and_then(|tr| self.self_type_matches_expected_vid(tr, expected_vid)) .and_then(|tr| self.tcx.lang_items.fn_trait_kind(tr.def_id())) }) - .fold(None, |best, cur| Some(best.map_or(cur, |best| cmp::min(best, cur)))); + .fold(None, + |best, cur| Some(best.map_or(cur, |best| cmp::min(best, cur)))); (expected_sig, expected_kind) } @@ -190,13 +196,11 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { /// Given a projection like "::Result == Y", we can deduce /// everything we need to know about a closure. fn deduce_sig_from_projection(&self, - projection: &ty::PolyProjectionPredicate<'tcx>) - -> Option> - { + projection: &ty::PolyProjectionPredicate<'tcx>) + -> Option> { let tcx = self.tcx; - debug!("deduce_sig_from_projection({:?})", - projection); + debug!("deduce_sig_from_projection({:?})", projection); let trait_ref = projection.to_poly_trait_ref(); @@ -206,22 +210,26 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { let arg_param_ty = trait_ref.substs().type_at(1); let arg_param_ty = self.resolve_type_vars_if_possible(&arg_param_ty); - debug!("deduce_sig_from_projection: arg_param_ty {:?}", arg_param_ty); + debug!("deduce_sig_from_projection: arg_param_ty {:?}", + arg_param_ty); let input_tys = match arg_param_ty.sty { ty::TyTuple(tys) => tys.to_vec(), - _ => { return None; } + _ => { + return None; + } }; debug!("deduce_sig_from_projection: input_tys {:?}", input_tys); let ret_param_ty = projection.0.ty; let ret_param_ty = self.resolve_type_vars_if_possible(&ret_param_ty); - debug!("deduce_sig_from_projection: ret_param_ty {:?}", ret_param_ty); + debug!("deduce_sig_from_projection: ret_param_ty {:?}", + ret_param_ty); let fn_sig = ty::FnSig { inputs: input_tys, output: ret_param_ty, - variadic: false + variadic: false, }; debug!("deduce_sig_from_projection: fn_sig {:?}", fn_sig); @@ -229,10 +237,9 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { } fn self_type_matches_expected_vid(&self, - trait_ref: ty::PolyTraitRef<'tcx>, - expected_vid: ty::TyVid) - -> Option> - { + trait_ref: ty::PolyTraitRef<'tcx>, + expected_vid: ty::TyVid) + -> Option> { let self_ty = self.shallow_resolve(trait_ref.self_ty()); debug!("self_type_matches_expected_vid(trait_ref={:?}, self_ty={:?})", trait_ref, diff --git a/src/librustc_typeck/check/coercion.rs b/src/librustc_typeck/check/coercion.rs index 98a05989b1..16493412d6 100644 --- a/src/librustc_typeck/check/coercion.rs +++ b/src/librustc_typeck/check/coercion.rs @@ -60,15 +60,12 @@ //! sort of a minor point so I've opted to leave it for later---after all //! we may want to adjust precisely when coercions occur. -use check::{FnCtxt}; +use check::FnCtxt; use rustc::hir; use rustc::infer::{Coercion, InferOk, TypeOrigin, TypeTrace}; use rustc::traits::{self, ObligationCause}; -use rustc::ty::adjustment::{AutoAdjustment, AutoDerefRef, AdjustDerefRef}; -use rustc::ty::adjustment::{AutoPtr, AutoUnsafe, AdjustReifyFnPointer}; -use rustc::ty::adjustment::{AdjustUnsafeFnPointer, AdjustMutToConstPointer}; -use rustc::ty::adjustment::AdjustNeverToAny; +use rustc::ty::adjustment::{Adjustment, Adjust, AutoBorrow}; use rustc::ty::{self, LvaluePreference, TypeAndMut, Ty}; use rustc::ty::fold::TypeFoldable; use rustc::ty::error::TypeError; @@ -79,7 +76,7 @@ use std::cell::RefCell; use std::collections::VecDeque; use std::ops::Deref; -struct Coerce<'a, 'gcx: 'a+'tcx, 'tcx: 'a> { +struct Coerce<'a, 'gcx: 'a + 'tcx, 'tcx: 'a> { fcx: &'a FnCtxt<'a, 'gcx, 'tcx>, origin: TypeOrigin, use_lub: bool, @@ -93,7 +90,7 @@ impl<'a, 'gcx, 'tcx> Deref for Coerce<'a, 'gcx, 'tcx> { } } -type CoerceResult<'tcx> = RelateResult<'tcx, (Ty<'tcx>, AutoAdjustment<'tcx>)>; +type CoerceResult<'tcx> = RelateResult<'tcx, (Ty<'tcx>, Adjust<'tcx>)>; fn coerce_mutbls<'tcx>(from_mutbl: hir::Mutability, to_mutbl: hir::Mutability) @@ -102,7 +99,7 @@ fn coerce_mutbls<'tcx>(from_mutbl: hir::Mutability, (hir::MutMutable, hir::MutMutable) | (hir::MutImmutable, hir::MutImmutable) | (hir::MutMutable, hir::MutImmutable) => Ok(()), - (hir::MutImmutable, hir::MutMutable) => Err(TypeError::Mutability) + (hir::MutImmutable, hir::MutMutable) => Err(TypeError::Mutability), } } @@ -112,7 +109,7 @@ impl<'f, 'gcx, 'tcx> Coerce<'f, 'gcx, 'tcx> { fcx: fcx, origin: origin, use_lub: false, - unsizing_obligations: RefCell::new(vec![]) + unsizing_obligations: RefCell::new(vec![]), } } @@ -144,21 +141,17 @@ impl<'f, 'gcx, 'tcx> Coerce<'f, 'gcx, 'tcx> { /// Synthesize an identity adjustment. fn identity(&self, ty: Ty<'tcx>) -> CoerceResult<'tcx> { - Ok((ty, AdjustDerefRef(AutoDerefRef { + Ok((ty, Adjust::DerefRef { autoderefs: 0, autoref: None, - unsize: None - }))) + unsize: false, + })) } - fn coerce<'a, E, I>(&self, - exprs: &E, - a: Ty<'tcx>, - b: Ty<'tcx>) - -> CoerceResult<'tcx> - // FIXME(eddyb) use copyable iterators when that becomes ergonomic. + fn coerce<'a, E, I>(&self, exprs: &E, a: Ty<'tcx>, b: Ty<'tcx>) -> CoerceResult<'tcx> where E: Fn() -> I, - I: IntoIterator { + I: IntoIterator + { let a = self.shallow_resolve(a); debug!("Coerce.tys({:?} => {:?})", a, b); @@ -169,7 +162,7 @@ impl<'f, 'gcx, 'tcx> Coerce<'f, 'gcx, 'tcx> { } if a.is_never() { - return Ok((b, AdjustNeverToAny(b))); + return Ok((b, Adjust::NeverToAny)); } // Consider coercing the subtype to a DST @@ -199,6 +192,8 @@ impl<'f, 'gcx, 'tcx> Coerce<'f, 'gcx, 'tcx> { // Function items are coercible to any closure // type; function pointers are not (that would // require double indirection). + // Additionally, we permit coercion of function + // items to drop the unsafe qualifier. self.coerce_from_fn_item(a, a_f, b) } ty::TyFnPtr(a_f) => { @@ -223,9 +218,8 @@ impl<'f, 'gcx, 'tcx> Coerce<'f, 'gcx, 'tcx> { r_b: &'tcx ty::Region, mt_b: TypeAndMut<'tcx>) -> CoerceResult<'tcx> - // FIXME(eddyb) use copyable iterators when that becomes ergonomic. where E: Fn() -> I, - I: IntoIterator + I: IntoIterator { debug!("coerce_borrowed_pointer(a={:?}, b={:?})", a, b); @@ -241,7 +235,7 @@ impl<'f, 'gcx, 'tcx> Coerce<'f, 'gcx, 'tcx> { coerce_mutbls(mt_a.mutbl, mt_b.mutbl)?; (r_a, mt_a) } - _ => return self.unify_and_identity(a, b) + _ => return self.unify_and_identity(a, b), }; let span = self.origin.span(); @@ -255,7 +249,7 @@ impl<'f, 'gcx, 'tcx> Coerce<'f, 'gcx, 'tcx> { if autoderefs == 0 { // Don't let this pass, otherwise it would cause // &T to autoref to &&T. - continue + continue; } // At this point, we have deref'd `a` to `referent_ty`. So @@ -333,19 +327,24 @@ impl<'f, 'gcx, 'tcx> Coerce<'f, 'gcx, 'tcx> { } else if autoderefs == 1 { r_a // [3] above } else { - if r_borrow_var.is_none() { // create var lazilly, at most once + if r_borrow_var.is_none() { + // create var lazilly, at most once let coercion = Coercion(span); let r = self.next_region_var(coercion); r_borrow_var = Some(r); // [4] above } r_borrow_var.unwrap() }; - let derefd_ty_a = self.tcx.mk_ref(r, TypeAndMut { - ty: referent_ty, - mutbl: mt_b.mutbl // [1] above - }); + let derefd_ty_a = self.tcx.mk_ref(r, + TypeAndMut { + ty: referent_ty, + mutbl: mt_b.mutbl, // [1] above + }); match self.unify(derefd_ty_a, b) { - Ok(ty) => { success = Some((ty, autoderefs)); break }, + Ok(ty) => { + success = Some((ty, autoderefs)); + break; + } Err(err) => { if first_error.is_none() { first_error = Some(err); @@ -391,29 +390,26 @@ impl<'f, 'gcx, 'tcx> Coerce<'f, 'gcx, 'tcx> { } let r_borrow = match ty.sty { ty::TyRef(r_borrow, _) => r_borrow, - _ => span_bug!(span, "expected a ref type, got {:?}", ty) + _ => span_bug!(span, "expected a ref type, got {:?}", ty), }; - let autoref = Some(AutoPtr(r_borrow, mt_b.mutbl)); + let autoref = Some(AutoBorrow::Ref(r_borrow, mt_b.mutbl)); debug!("coerce_borrowed_pointer: succeeded ty={:?} autoderefs={:?} autoref={:?}", - ty, autoderefs, autoref); - Ok((ty, AdjustDerefRef(AutoDerefRef { + ty, + autoderefs, + autoref); + Ok((ty, Adjust::DerefRef { autoderefs: autoderefs, autoref: autoref, - unsize: None - }))) + unsize: false, + })) } // &[T; n] or &mut [T; n] -> &[T] // or &mut [T; n] -> &mut [T] // or &Concrete -> &Trait, etc. - fn coerce_unsized(&self, - source: Ty<'tcx>, - target: Ty<'tcx>) - -> CoerceResult<'tcx> { - debug!("coerce_unsized(source={:?}, target={:?})", - source, - target); + fn coerce_unsized(&self, source: Ty<'tcx>, target: Ty<'tcx>) -> CoerceResult<'tcx> { + debug!("coerce_unsized(source={:?}, target={:?})", source, target); let traits = (self.tcx.lang_items.unsize_trait(), self.tcx.lang_items.coerce_unsized_trait()); @@ -436,13 +432,13 @@ impl<'f, 'gcx, 'tcx> Coerce<'f, 'gcx, 'tcx> { let coercion = Coercion(self.origin.span()); let r_borrow = self.next_region_var(coercion); - (mt_a.ty, Some(AutoPtr(r_borrow, mt_b.mutbl))) + (mt_a.ty, Some(AutoBorrow::Ref(r_borrow, mt_b.mutbl))) } (&ty::TyRef(_, mt_a), &ty::TyRawPtr(mt_b)) => { coerce_mutbls(mt_a.mutbl, mt_b.mutbl)?; - (mt_a.ty, Some(AutoUnsafe(mt_b.mutbl))) + (mt_a.ty, Some(AutoBorrow::RawPtr(mt_b.mutbl))) } - _ => (source, None) + _ => (source, None), }; let source = source.adjust_for_autoref(self.tcx, reborrow); @@ -454,11 +450,8 @@ impl<'f, 'gcx, 'tcx> Coerce<'f, 'gcx, 'tcx> { // Create an obligation for `Source: CoerceUnsized`. let cause = ObligationCause::misc(self.origin.span(), self.body_id); - queue.push_back(self.tcx.predicate_for_trait_def(cause, - coerce_unsized_did, - 0, - source, - &[target])); + queue.push_back(self.tcx + .predicate_for_trait_def(cause, coerce_unsized_did, 0, source, &[target])); // Keep resolving `CoerceUnsized` and `Unsize` predicates to avoid // emitting a coercion in cases like `Foo<$1>` -> `Foo<$2>`, where @@ -466,10 +459,8 @@ impl<'f, 'gcx, 'tcx> Coerce<'f, 'gcx, 'tcx> { let traits = [coerce_unsized_did, unsize_did]; while let Some(obligation) = queue.pop_front() { debug!("coerce_unsized resolve step: {:?}", obligation); - let trait_ref = match obligation.predicate { - ty::Predicate::Trait(ref tr) if traits.contains(&tr.def_id()) => { - tr.clone() - } + let trait_ref = match obligation.predicate { + ty::Predicate::Trait(ref tr) if traits.contains(&tr.def_id()) => tr.clone(), _ => { leftover_predicates.push(obligation); continue; @@ -477,7 +468,8 @@ impl<'f, 'gcx, 'tcx> Coerce<'f, 'gcx, 'tcx> { }; match selcx.select(&obligation.with(trait_ref)) { // Uncertain or unimplemented. - Ok(None) | Err(traits::Unimplemented) => { + Ok(None) | + Err(traits::Unimplemented) => { debug!("coerce_unsized: early return - can't prove obligation"); return Err(TypeError::Mismatch); } @@ -500,36 +492,26 @@ impl<'f, 'gcx, 'tcx> Coerce<'f, 'gcx, 'tcx> { *self.unsizing_obligations.borrow_mut() = leftover_predicates; - let adjustment = AutoDerefRef { + let adjustment = Adjust::DerefRef { autoderefs: if reborrow.is_some() { 1 } else { 0 }, autoref: reborrow, - unsize: Some(target) + unsize: true, }; debug!("Success, coerced with {:?}", adjustment); - Ok((target, AdjustDerefRef(adjustment))) + Ok((target, adjustment)) } - fn coerce_from_fn_pointer(&self, + fn coerce_from_safe_fn(&self, a: Ty<'tcx>, fn_ty_a: &'tcx ty::BareFnTy<'tcx>, b: Ty<'tcx>) - -> CoerceResult<'tcx> - { - /*! - * Attempts to coerce from the type of a Rust function item - * into a closure or a `proc`. - */ - - let b = self.shallow_resolve(b); - debug!("coerce_from_fn_pointer(a={:?}, b={:?})", a, b); - + -> CoerceResult<'tcx> { if let ty::TyFnPtr(fn_ty_b) = b.sty { match (fn_ty_a.unsafety, fn_ty_b.unsafety) { (hir::Unsafety::Normal, hir::Unsafety::Unsafe) => { let unsafe_a = self.tcx.safe_to_unsafe_fn_ty(fn_ty_a); - return self.unify_and_identity(unsafe_a, b).map(|(ty, _)| { - (ty, AdjustUnsafeFnPointer) - }); + return self.unify_and_identity(unsafe_a, b) + .map(|(ty, _)| (ty, Adjust::UnsafeFnPointer)); } _ => {} } @@ -537,15 +519,29 @@ impl<'f, 'gcx, 'tcx> Coerce<'f, 'gcx, 'tcx> { self.unify_and_identity(a, b) } + fn coerce_from_fn_pointer(&self, + a: Ty<'tcx>, + fn_ty_a: &'tcx ty::BareFnTy<'tcx>, + b: Ty<'tcx>) + -> CoerceResult<'tcx> { + //! Attempts to coerce from the type of a Rust function item + //! into a closure or a `proc`. + //! + + let b = self.shallow_resolve(b); + debug!("coerce_from_fn_pointer(a={:?}, b={:?})", a, b); + + self.coerce_from_safe_fn(a, fn_ty_a, b) + } + fn coerce_from_fn_item(&self, a: Ty<'tcx>, fn_ty_a: &'tcx ty::BareFnTy<'tcx>, b: Ty<'tcx>) -> CoerceResult<'tcx> { - /*! - * Attempts to coerce from the type of a Rust function item - * into a closure or a `proc`. - */ + //! Attempts to coerce from the type of a Rust function item + //! into a closure or a `proc`. + //! let b = self.shallow_resolve(b); debug!("coerce_from_fn_item(a={:?}, b={:?})", a, b); @@ -553,11 +549,10 @@ impl<'f, 'gcx, 'tcx> Coerce<'f, 'gcx, 'tcx> { match b.sty { ty::TyFnPtr(_) => { let a_fn_pointer = self.tcx.mk_fn_ptr(fn_ty_a); - self.unify_and_identity(a_fn_pointer, b).map(|(ty, _)| { - (ty, AdjustReifyFnPointer) - }) + self.coerce_from_safe_fn(a_fn_pointer, fn_ty_a, b) + .map(|(ty, _)| (ty, Adjust::ReifyFnPointer)) } - _ => self.unify_and_identity(a, b) + _ => self.unify_and_identity(a, b), } } @@ -566,9 +561,7 @@ impl<'f, 'gcx, 'tcx> Coerce<'f, 'gcx, 'tcx> { b: Ty<'tcx>, mutbl_b: hir::Mutability) -> CoerceResult<'tcx> { - debug!("coerce_unsafe_ptr(a={:?}, b={:?})", - a, - b); + debug!("coerce_unsafe_ptr(a={:?}, b={:?})", a, b); let (is_ref, mt_a) = match a.sty { ty::TyRef(_, mt) => (true, mt), @@ -579,24 +572,28 @@ impl<'f, 'gcx, 'tcx> Coerce<'f, 'gcx, 'tcx> { }; // Check that the types which they point at are compatible. - let a_unsafe = self.tcx.mk_ptr(ty::TypeAndMut{ mutbl: mutbl_b, ty: mt_a.ty }); + let a_unsafe = self.tcx.mk_ptr(ty::TypeAndMut { + mutbl: mutbl_b, + ty: mt_a.ty, + }); let (ty, noop) = self.unify_and_identity(a_unsafe, b)?; coerce_mutbls(mt_a.mutbl, mutbl_b)?; // Although references and unsafe ptrs have the same - // representation, we still register an AutoDerefRef so that + // representation, we still register an Adjust::DerefRef so that // regionck knows that the region for `a` must be valid here. - Ok((ty, if is_ref { - AdjustDerefRef(AutoDerefRef { - autoderefs: 1, - autoref: Some(AutoUnsafe(mutbl_b)), - unsize: None - }) - } else if mt_a.mutbl != mutbl_b { - AdjustMutToConstPointer - } else { - noop - })) + Ok((ty, + if is_ref { + Adjust::DerefRef { + autoderefs: 1, + autoref: Some(AutoBorrow::RawPtr(mutbl_b)), + unsize: false, + } + } else if mt_a.mutbl != mutbl_b { + Adjust::MutToConstPointer + } else { + noop + })) } } @@ -604,23 +601,25 @@ fn apply<'a, 'b, 'gcx, 'tcx, E, I>(coerce: &mut Coerce<'a, 'gcx, 'tcx>, exprs: &E, a: Ty<'tcx>, b: Ty<'tcx>) - -> CoerceResult<'tcx> + -> RelateResult<'tcx, Adjustment<'tcx>> where E: Fn() -> I, - I: IntoIterator { + I: IntoIterator +{ - let (ty, adjustment) = indent(|| coerce.coerce(exprs, a, b))?; + let (ty, adjust) = indent(|| coerce.coerce(exprs, a, b))?; let fcx = coerce.fcx; - if let AdjustDerefRef(auto) = adjustment { - if auto.unsize.is_some() { - let mut obligations = coerce.unsizing_obligations.borrow_mut(); - for obligation in obligations.drain(..) { - fcx.register_predicate(obligation); - } + if let Adjust::DerefRef { unsize: true, .. } = adjust { + let mut obligations = coerce.unsizing_obligations.borrow_mut(); + for obligation in obligations.drain(..) { + fcx.register_predicate(obligation); } } - Ok((ty, adjustment)) + Ok(Adjustment { + kind: adjust, + target: ty + }) } impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { @@ -638,17 +637,17 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { let mut coerce = Coerce::new(self, TypeOrigin::ExprAssignable(expr.span)); self.commit_if_ok(|_| { - let (ty, adjustment) = - apply(&mut coerce, &|| Some(expr), source, target)?; + let adjustment = apply(&mut coerce, &|| Some(expr), source, target)?; if !adjustment.is_identity() { debug!("Success, coerced with {:?}", adjustment); match self.tables.borrow().adjustments.get(&expr.id) { - None | Some(&AdjustNeverToAny(..)) => (), + None | + Some(&Adjustment { kind: Adjust::NeverToAny, .. }) => (), _ => bug!("expr already has an adjustment on it!"), }; self.write_adjustment(expr.id, adjustment); } - Ok(ty) + Ok(adjustment.target) }) } @@ -662,9 +661,9 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { new: &'b hir::Expr, new_ty: Ty<'tcx>) -> RelateResult<'tcx, Ty<'tcx>> - // FIXME(eddyb) use copyable iterators when that becomes ergonomic. where E: Fn() -> I, - I: IntoIterator { + I: IntoIterator + { let prev_ty = self.resolve_type_vars_with_obligations(prev_ty); let new_ty = self.resolve_type_vars_with_obligations(new_ty); @@ -675,8 +674,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { // Special-case that coercion alone cannot handle: // Two function item types of differing IDs or Substs. match (&prev_ty.sty, &new_ty.sty) { - (&ty::TyFnDef(a_def_id, a_substs, a_fty), - &ty::TyFnDef(b_def_id, b_substs, b_fty)) => { + (&ty::TyFnDef(a_def_id, a_substs, a_fty), &ty::TyFnDef(b_def_id, b_substs, b_fty)) => { // The signature must always match. let fty = self.lub(true, trace.clone(), &a_fty, &b_fty) .map(|InferOk { value, obligations }| { @@ -703,12 +701,16 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { } // Reify both sides and return the reified fn pointer type. + let fn_ptr = self.tcx.mk_fn_ptr(fty); for expr in exprs().into_iter().chain(Some(new)) { // No adjustments can produce a fn item, so this should never trip. assert!(!self.tables.borrow().adjustments.contains_key(&expr.id)); - self.write_adjustment(expr.id, AdjustReifyFnPointer); + self.write_adjustment(expr.id, Adjustment { + kind: Adjust::ReifyFnPointer, + target: fn_ptr + }); } - return Ok(self.tcx.mk_fn_ptr(fty)); + return Ok(fn_ptr); } _ => {} } @@ -720,17 +722,15 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { // but only if the new expression has no coercion already applied to it. let mut first_error = None; if !self.tables.borrow().adjustments.contains_key(&new.id) { - let result = self.commit_if_ok(|_| { - apply(&mut coerce, &|| Some(new), new_ty, prev_ty) - }); + let result = self.commit_if_ok(|_| apply(&mut coerce, &|| Some(new), new_ty, prev_ty)); match result { - Ok((ty, adjustment)) => { + Ok(adjustment) => { if !adjustment.is_identity() { self.write_adjustment(new.id, adjustment); } - return Ok(ty); + return Ok(adjustment.target); } - Err(e) => first_error = Some(e) + Err(e) => first_error = Some(e), } } @@ -738,21 +738,23 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { // This requires ensuring there are no coercions applied to *any* of the // previous expressions, other than noop reborrows (ignoring lifetimes). for expr in exprs() { - let noop = match self.tables.borrow().adjustments.get(&expr.id) { - Some(&AdjustDerefRef(AutoDerefRef { + let noop = match self.tables.borrow().adjustments.get(&expr.id).map(|adj| adj.kind) { + Some(Adjust::DerefRef { autoderefs: 1, - autoref: Some(AutoPtr(_, mutbl_adj)), - unsize: None - })) => match self.node_ty(expr.id).sty { - ty::TyRef(_, mt_orig) => { - // Reborrow that we can safely ignore. - mutbl_adj == mt_orig.mutbl + autoref: Some(AutoBorrow::Ref(_, mutbl_adj)), + unsize: false + }) => { + match self.node_ty(expr.id).sty { + ty::TyRef(_, mt_orig) => { + // Reborrow that we can safely ignore. + mutbl_adj == mt_orig.mutbl + } + _ => false, } - _ => false - }, - Some(&AdjustNeverToAny(_)) => true, + } + Some(Adjust::NeverToAny) => true, Some(_) => false, - None => true + None => true, }; if !noop { @@ -783,18 +785,21 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { }) } } - Ok((ty, adjustment)) => { + Ok(adjustment) => { if !adjustment.is_identity() { + let mut tables = self.tables.borrow_mut(); for expr in exprs() { - let previous = self.tables.borrow().adjustments.get(&expr.id).cloned(); - if let Some(AdjustNeverToAny(_)) = previous { - self.write_adjustment(expr.id, AdjustNeverToAny(ty)); - } else { - self.write_adjustment(expr.id, adjustment); + if let Some(&mut Adjustment { + kind: Adjust::NeverToAny, + ref mut target + }) = tables.adjustments.get_mut(&expr.id) { + *target = adjustment.target; + continue; } + tables.adjustments.insert(expr.id, adjustment); } } - Ok(ty) + Ok(adjustment.target) } } } diff --git a/src/librustc_typeck/check/compare_method.rs b/src/librustc_typeck/check/compare_method.rs index ffff05885a..2cb719675a 100644 --- a/src/librustc_typeck/check/compare_method.rs +++ b/src/librustc_typeck/check/compare_method.rs @@ -8,19 +8,21 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -use middle::free_region::FreeRegionMap; use rustc::infer::{self, InferOk, TypeOrigin}; +use rustc::middle::free_region::FreeRegionMap; use rustc::ty; use rustc::traits::{self, Reveal}; use rustc::ty::error::{ExpectedFound, TypeError}; use rustc::ty::subst::{Subst, Substs}; use rustc::hir::{ImplItemKind, TraitItem_, Ty_}; +use rustc::util::common::ErrorReported; use syntax::ast; use syntax_pos::Span; use CrateCtxt; use super::assoc; +use super::{Inherited, FnCtxt}; /// Checks that a method from an impl conforms to the signature of /// the same method as declared in the trait. @@ -39,125 +41,56 @@ pub fn compare_impl_method<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>, impl_m_body_id: ast::NodeId, trait_m: &ty::Method<'tcx>, impl_trait_ref: &ty::TraitRef<'tcx>, - trait_item_span: Option) { + trait_item_span: Option, + old_broken_mode: bool) { debug!("compare_impl_method(impl_trait_ref={:?})", impl_trait_ref); - debug!("compare_impl_method: impl_trait_ref (liberated) = {:?}", - impl_trait_ref); - - let tcx = ccx.tcx; - - let trait_to_impl_substs = &impl_trait_ref.substs; - - // Try to give more informative error messages about self typing - // mismatches. Note that any mismatch will also be detected - // below, where we construct a canonical function type that - // includes the self parameter as a normal parameter. It's just - // that the error messages you get out of this code are a bit more - // inscrutable, particularly for cases where one method has no - // self. - match (&trait_m.explicit_self, &impl_m.explicit_self) { - (&ty::ExplicitSelfCategory::Static, - &ty::ExplicitSelfCategory::Static) => {} - (&ty::ExplicitSelfCategory::Static, _) => { - let mut err = struct_span_err!(tcx.sess, impl_m_span, E0185, - "method `{}` has a `{}` declaration in the impl, \ - but not in the trait", - trait_m.name, - impl_m.explicit_self); - err.span_label(impl_m_span, &format!("`{}` used in impl", - impl_m.explicit_self)); - if let Some(span) = tcx.map.span_if_local(trait_m.def_id) { - err.span_label(span, &format!("trait declared without `{}`", - impl_m.explicit_self)); - } - err.emit(); - return; - } - (_, &ty::ExplicitSelfCategory::Static) => { - let mut err = struct_span_err!(tcx.sess, impl_m_span, E0186, - "method `{}` has a `{}` declaration in the trait, \ - but not in the impl", - trait_m.name, - trait_m.explicit_self); - err.span_label(impl_m_span, &format!("expected `{}` in impl", - trait_m.explicit_self)); - if let Some(span) = tcx.map.span_if_local(trait_m.def_id) { - err.span_label(span, & format!("`{}` used in trait", - trait_m.explicit_self)); - } - err.emit(); - return; - } - _ => { - // Let the type checker catch other errors below - } + if let Err(ErrorReported) = compare_self_type(ccx, + impl_m, + impl_m_span, + trait_m) { + return; } - let num_impl_m_type_params = impl_m.generics.types.len(); - let num_trait_m_type_params = trait_m.generics.types.len(); - if num_impl_m_type_params != num_trait_m_type_params { - let impl_m_node_id = tcx.map.as_local_node_id(impl_m.def_id).unwrap(); - let span = match tcx.map.expect_impl_item(impl_m_node_id).node { - ImplItemKind::Method(ref impl_m_sig, _) => { - if impl_m_sig.generics.is_parameterized() { - impl_m_sig.generics.span - } else { - impl_m_span - } - } - _ => bug!("{:?} is not a method", impl_m) - }; - - let mut err = struct_span_err!(tcx.sess, span, E0049, - "method `{}` has {} type parameter{} \ - but its trait declaration has {} type parameter{}", - trait_m.name, - num_impl_m_type_params, - if num_impl_m_type_params == 1 {""} else {"s"}, - num_trait_m_type_params, - if num_trait_m_type_params == 1 {""} else {"s"}); - - let mut suffix = None; - - if let Some(span) = trait_item_span { - err.span_label(span, - &format!("expected {}", - &if num_trait_m_type_params != 1 { - format!("{} type parameters", num_trait_m_type_params) - } else { - format!("{} type parameter", num_trait_m_type_params) - })); - } else { - suffix = Some(format!(", expected {}", num_trait_m_type_params)); - } - - err.span_label(span, - &format!("found {}{}", - &if num_impl_m_type_params != 1 { - format!("{} type parameters", num_impl_m_type_params) - } else { - format!("1 type parameter") - }, - suffix.as_ref().map(|s| &s[..]).unwrap_or(""))); - - err.emit(); + if let Err(ErrorReported) = compare_number_of_generics(ccx, + impl_m, + impl_m_span, + trait_m, + trait_item_span) { + return; + } + if let Err(ErrorReported) = compare_number_of_method_arguments(ccx, + impl_m, + impl_m_span, + trait_m, + trait_item_span) { return; } - if impl_m.fty.sig.0.inputs.len() != trait_m.fty.sig.0.inputs.len() { - span_err!(tcx.sess, impl_m_span, E0050, - "method `{}` has {} parameter{} \ - but the declaration in trait `{}` has {}", - trait_m.name, - impl_m.fty.sig.0.inputs.len(), - if impl_m.fty.sig.0.inputs.len() == 1 {""} else {"s"}, - tcx.item_path_str(trait_m.def_id), - trait_m.fty.sig.0.inputs.len()); + if let Err(ErrorReported) = compare_predicate_entailment(ccx, + impl_m, + impl_m_span, + impl_m_body_id, + trait_m, + impl_trait_ref, + old_broken_mode) { return; } +} + +fn compare_predicate_entailment<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>, + impl_m: &ty::Method<'tcx>, + impl_m_span: Span, + impl_m_body_id: ast::NodeId, + trait_m: &ty::Method<'tcx>, + impl_trait_ref: &ty::TraitRef<'tcx>, + old_broken_mode: bool) + -> Result<(), ErrorReported> { + let tcx = ccx.tcx; + + let trait_to_impl_substs = &impl_trait_ref.substs; // This code is best explained by example. Consider a trait: // @@ -231,69 +164,65 @@ pub fn compare_impl_method<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>, let impl_to_skol_substs = &impl_param_env.free_substs; // Create mapping from trait to skolemized. - let trait_to_skol_substs = - impl_to_skol_substs.rebase_onto(tcx, impl_m.container_id(), - trait_to_impl_substs.subst(tcx, impl_to_skol_substs)); + let trait_to_skol_substs = impl_to_skol_substs.rebase_onto(tcx, + impl_m.container_id(), + trait_to_impl_substs.subst(tcx, + impl_to_skol_substs)); debug!("compare_impl_method: trait_to_skol_substs={:?}", trait_to_skol_substs); - // Check region bounds. FIXME(@jroesch) refactor this away when removing - // ParamBounds. - if !check_region_bounds_on_impl_method(ccx, - impl_m_span, - impl_m, - &trait_m.generics, - &impl_m.generics, - trait_to_skol_substs, - impl_to_skol_substs) { - return; - } - - tcx.infer_ctxt(None, None, Reveal::NotSpecializable).enter(|mut infcx| { - let mut fulfillment_cx = traits::FulfillmentContext::new(); - - // Create obligations for each predicate declared by the impl - // definition in the context of the trait's parameter - // environment. We can't just use `impl_env.caller_bounds`, - // however, because we want to replace all late-bound regions with - // region variables. - let impl_predicates = tcx.lookup_predicates(impl_m.predicates.parent.unwrap()); - let mut hybrid_preds = impl_predicates.instantiate(tcx, impl_to_skol_substs); - - debug!("compare_impl_method: impl_bounds={:?}", hybrid_preds); - - // This is the only tricky bit of the new way we check implementation methods - // We need to build a set of predicates where only the method-level bounds - // are from the trait and we assume all other bounds from the implementation - // to be previously satisfied. - // - // We then register the obligations from the impl_m and check to see - // if all constraints hold. - hybrid_preds.predicates.extend( - trait_m.predicates.instantiate_own(tcx, trait_to_skol_substs).predicates); - - // Construct trait parameter environment and then shift it into the skolemized viewpoint. - // The key step here is to update the caller_bounds's predicates to be - // the new hybrid bounds we computed. - let normalize_cause = traits::ObligationCause::misc(impl_m_span, impl_m_body_id); - let trait_param_env = impl_param_env.with_caller_bounds(hybrid_preds.predicates); - let trait_param_env = traits::normalize_param_env_or_error(tcx, - trait_param_env, - normalize_cause.clone()); - // FIXME(@jroesch) this seems ugly, but is a temporary change - infcx.parameter_environment = trait_param_env; + // Check region bounds. + check_region_bounds_on_impl_method(ccx, + impl_m_span, + impl_m, + &trait_m.generics, + &impl_m.generics, + trait_to_skol_substs, + impl_to_skol_substs)?; + + // Create obligations for each predicate declared by the impl + // definition in the context of the trait's parameter + // environment. We can't just use `impl_env.caller_bounds`, + // however, because we want to replace all late-bound regions with + // region variables. + let impl_predicates = tcx.lookup_predicates(impl_m.predicates.parent.unwrap()); + let mut hybrid_preds = impl_predicates.instantiate(tcx, impl_to_skol_substs); + + debug!("compare_impl_method: impl_bounds={:?}", hybrid_preds); + + // This is the only tricky bit of the new way we check implementation methods + // We need to build a set of predicates where only the method-level bounds + // are from the trait and we assume all other bounds from the implementation + // to be previously satisfied. + // + // We then register the obligations from the impl_m and check to see + // if all constraints hold. + hybrid_preds.predicates + .extend(trait_m.predicates.instantiate_own(tcx, trait_to_skol_substs).predicates); + + // Construct trait parameter environment and then shift it into the skolemized viewpoint. + // The key step here is to update the caller_bounds's predicates to be + // the new hybrid bounds we computed. + let normalize_cause = traits::ObligationCause::misc(impl_m_span, impl_m_body_id); + let trait_param_env = impl_param_env.with_caller_bounds(hybrid_preds.predicates); + let trait_param_env = traits::normalize_param_env_or_error(tcx, + trait_param_env, + normalize_cause.clone()); + + tcx.infer_ctxt(None, Some(trait_param_env), Reveal::NotSpecializable).enter(|infcx| { + let inh = Inherited::new(ccx, infcx); + let infcx = &inh.infcx; + let fulfillment_cx = &inh.fulfillment_cx; debug!("compare_impl_method: caller_bounds={:?}", - infcx.parameter_environment.caller_bounds); + infcx.parameter_environment.caller_bounds); let mut selcx = traits::SelectionContext::new(&infcx); let impl_m_own_bounds = impl_m.predicates.instantiate_own(tcx, impl_to_skol_substs); - let (impl_m_own_bounds, _) = - infcx.replace_late_bound_regions_with_fresh_var( - impl_m_span, - infer::HigherRankedType, - &ty::Binder(impl_m_own_bounds.predicates)); + let (impl_m_own_bounds, _) = infcx.replace_late_bound_regions_with_fresh_var(impl_m_span, + infer::HigherRankedType, + &ty::Binder(impl_m_own_bounds.predicates)); for predicate in impl_m_own_bounds { let traits::Normalized { value: predicate, .. } = traits::normalize(&mut selcx, normalize_cause.clone(), &predicate); @@ -301,10 +230,15 @@ pub fn compare_impl_method<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>, let cause = traits::ObligationCause { span: impl_m_span, body_id: impl_m_body_id, - code: traits::ObligationCauseCode::CompareImplMethodObligation + code: traits::ObligationCauseCode::CompareImplMethodObligation { + item_name: impl_m.name, + impl_item_def_id: impl_m.def_id, + trait_item_def_id: trait_m.def_id, + lint_id: if !old_broken_mode { Some(impl_m_body_id) } else { None }, + }, }; - fulfillment_cx.register_predicate_obligation( + fulfillment_cx.borrow_mut().register_predicate_obligation( &infcx, traits::Obligation::new(cause, predicate)); } @@ -334,14 +268,14 @@ pub fn compare_impl_method<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>, impl_sig.subst(tcx, impl_to_skol_substs); let impl_sig = assoc::normalize_associated_types_in(&infcx, - &mut fulfillment_cx, + &mut fulfillment_cx.borrow_mut(), impl_m_span, impl_m_body_id, &impl_sig); let impl_fty = tcx.mk_fn_ptr(tcx.mk_bare_fn(ty::BareFnTy { unsafety: impl_m.fty.unsafety, abi: impl_m.fty.abi, - sig: ty::Binder(impl_sig.clone()) + sig: ty::Binder(impl_sig.clone()), })); debug!("compare_impl_method: impl_fty={:?}", impl_fty); @@ -352,194 +286,425 @@ pub fn compare_impl_method<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>, trait_sig.subst(tcx, trait_to_skol_substs); let trait_sig = assoc::normalize_associated_types_in(&infcx, - &mut fulfillment_cx, + &mut fulfillment_cx.borrow_mut(), impl_m_span, impl_m_body_id, &trait_sig); let trait_fty = tcx.mk_fn_ptr(tcx.mk_bare_fn(ty::BareFnTy { unsafety: trait_m.fty.unsafety, abi: trait_m.fty.abi, - sig: ty::Binder(trait_sig.clone()) + sig: ty::Binder(trait_sig.clone()), })); debug!("compare_impl_method: trait_fty={:?}", trait_fty); - if let Err(terr) = infcx.sub_types(false, origin, impl_fty, trait_fty) { + let sub_result = infcx.sub_types(false, origin, impl_fty, trait_fty) + .map(|InferOk { obligations, .. }| { + // FIXME(#32730) propagate obligations + assert!(obligations.is_empty()); + }); + + if let Err(terr) = sub_result { debug!("sub_types failed: impl ty {:?}, trait ty {:?}", impl_fty, trait_fty); - let (impl_err_span, trait_err_span) = - extract_spans_for_error_reporting(&infcx, &terr, origin, impl_m, - impl_sig, trait_m, trait_sig); + let (impl_err_span, trait_err_span) = extract_spans_for_error_reporting(&infcx, + &terr, + origin, + impl_m, + impl_sig, + trait_m, + trait_sig); let origin = TypeOrigin::MethodCompatCheck(impl_err_span); - let mut diag = struct_span_err!( - tcx.sess, origin.span(), E0053, - "method `{}` has an incompatible type for trait", trait_m.name - ); - - infcx.note_type_err( - &mut diag, - origin, - trait_err_span.map(|sp| (sp, format!("type in trait"))), - Some(infer::ValuePairs::Types(ExpectedFound { - expected: trait_fty, - found: impl_fty - })), - &terr - ); + let mut diag = struct_span_err!(tcx.sess, + origin.span(), + E0053, + "method `{}` has an incompatible type for trait", + trait_m.name); + + infcx.note_type_err(&mut diag, + origin, + trait_err_span.map(|sp| (sp, format!("type in trait"))), + Some(infer::ValuePairs::Types(ExpectedFound { + expected: trait_fty, + found: impl_fty, + })), + &terr); diag.emit(); - return + return Err(ErrorReported); } // Check that all obligations are satisfied by the implementation's // version. - if let Err(ref errors) = fulfillment_cx.select_all_or_error(&infcx) { + if let Err(ref errors) = fulfillment_cx.borrow_mut().select_all_or_error(&infcx) { infcx.report_fulfillment_errors(errors); - return + return Err(ErrorReported); } // Finally, resolve all regions. This catches wily misuses of - // lifetime parameters. We have to build up a plausible lifetime - // environment based on what we find in the trait. We could also - // include the obligations derived from the method argument types, - // but I don't think it's necessary -- after all, those are still - // in effect when type-checking the body, and all the - // where-clauses in the header etc should be implied by the trait - // anyway, so it shouldn't be needed there either. Anyway, we can - // always add more relations later (it's backwards compat). - let mut free_regions = FreeRegionMap::new(); - free_regions.relate_free_regions_from_predicates( - &infcx.parameter_environment.caller_bounds); - - infcx.resolve_regions_and_report_errors(&free_regions, impl_m_body_id); - }); - - fn check_region_bounds_on_impl_method<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>, - span: Span, - impl_m: &ty::Method<'tcx>, - trait_generics: &ty::Generics<'tcx>, - impl_generics: &ty::Generics<'tcx>, - trait_to_skol_substs: &Substs<'tcx>, - impl_to_skol_substs: &Substs<'tcx>) - -> bool - { - - let trait_params = &trait_generics.regions[..]; - let impl_params = &impl_generics.regions[..]; - - debug!("check_region_bounds_on_impl_method: \ - trait_generics={:?} \ - impl_generics={:?} \ - trait_to_skol_substs={:?} \ - impl_to_skol_substs={:?}", - trait_generics, - impl_generics, - trait_to_skol_substs, - impl_to_skol_substs); - - // Must have same number of early-bound lifetime parameters. - // Unfortunately, if the user screws up the bounds, then this - // will change classification between early and late. E.g., - // if in trait we have `<'a,'b:'a>`, and in impl we just have - // `<'a,'b>`, then we have 2 early-bound lifetime parameters - // in trait but 0 in the impl. But if we report "expected 2 - // but found 0" it's confusing, because it looks like there - // are zero. Since I don't quite know how to phrase things at - // the moment, give a kind of vague error message. - if trait_params.len() != impl_params.len() { - struct_span_err!(ccx.tcx.sess, span, E0195, - "lifetime parameters or bounds on method `{}` do \ - not match the trait declaration",impl_m.name) - .span_label(span, &format!("lifetimes do not match trait")) - .emit(); - return false; + // lifetime parameters. + if old_broken_mode { + // FIXME(#18937) -- this is how the code used to + // work. This is buggy because the fulfillment cx creates + // region obligations that get overlooked. The right + // thing to do is the code below. But we keep this old + // pass around temporarily. + let mut free_regions = FreeRegionMap::new(); + free_regions.relate_free_regions_from_predicates( + &infcx.parameter_environment.caller_bounds); + infcx.resolve_regions_and_report_errors(&free_regions, impl_m_body_id); + } else { + let fcx = FnCtxt::new(&inh, tcx.types.err, impl_m_body_id); + fcx.regionck_item(impl_m_body_id, impl_m_span, &[]); } - return true; + Ok(()) + }) +} + +fn check_region_bounds_on_impl_method<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>, + span: Span, + impl_m: &ty::Method<'tcx>, + trait_generics: &ty::Generics<'tcx>, + impl_generics: &ty::Generics<'tcx>, + trait_to_skol_substs: &Substs<'tcx>, + impl_to_skol_substs: &Substs<'tcx>) + -> Result<(), ErrorReported> { + let trait_params = &trait_generics.regions[..]; + let impl_params = &impl_generics.regions[..]; + + debug!("check_region_bounds_on_impl_method: \ + trait_generics={:?} \ + impl_generics={:?} \ + trait_to_skol_substs={:?} \ + impl_to_skol_substs={:?}", + trait_generics, + impl_generics, + trait_to_skol_substs, + impl_to_skol_substs); + + // Must have same number of early-bound lifetime parameters. + // Unfortunately, if the user screws up the bounds, then this + // will change classification between early and late. E.g., + // if in trait we have `<'a,'b:'a>`, and in impl we just have + // `<'a,'b>`, then we have 2 early-bound lifetime parameters + // in trait but 0 in the impl. But if we report "expected 2 + // but found 0" it's confusing, because it looks like there + // are zero. Since I don't quite know how to phrase things at + // the moment, give a kind of vague error message. + if trait_params.len() != impl_params.len() { + struct_span_err!(ccx.tcx.sess, + span, + E0195, + "lifetime parameters or bounds on method `{}` do not match the \ + trait declaration", + impl_m.name) + .span_label(span, &format!("lifetimes do not match trait")) + .emit(); + return Err(ErrorReported); } - fn extract_spans_for_error_reporting<'a, 'gcx, 'tcx>(infcx: &infer::InferCtxt<'a, 'gcx, 'tcx>, - terr: &TypeError, - origin: TypeOrigin, - impl_m: &ty::Method, - impl_sig: ty::FnSig<'tcx>, - trait_m: &ty::Method, - trait_sig: ty::FnSig<'tcx>) - -> (Span, Option) { - let tcx = infcx.tcx; - let impl_m_node_id = tcx.map.as_local_node_id(impl_m.def_id).unwrap(); - let (impl_m_output, impl_m_iter) = match tcx.map.expect_impl_item(impl_m_node_id).node { - ImplItemKind::Method(ref impl_m_sig, _) => - (&impl_m_sig.decl.output, impl_m_sig.decl.inputs.iter()), - _ => bug!("{:?} is not a method", impl_m) - }; + return Ok(()); +} - match *terr { - TypeError::Mutability => { - if let Some(trait_m_node_id) = tcx.map.as_local_node_id(trait_m.def_id) { - let trait_m_iter = match tcx.map.expect_trait_item(trait_m_node_id).node { - TraitItem_::MethodTraitItem(ref trait_m_sig, _) => - trait_m_sig.decl.inputs.iter(), - _ => bug!("{:?} is not a MethodTraitItem", trait_m) +fn extract_spans_for_error_reporting<'a, 'gcx, 'tcx>(infcx: &infer::InferCtxt<'a, 'gcx, 'tcx>, + terr: &TypeError, + origin: TypeOrigin, + impl_m: &ty::Method, + impl_sig: ty::FnSig<'tcx>, + trait_m: &ty::Method, + trait_sig: ty::FnSig<'tcx>) + -> (Span, Option) { + let tcx = infcx.tcx; + let impl_m_node_id = tcx.map.as_local_node_id(impl_m.def_id).unwrap(); + let (impl_m_output, impl_m_iter) = match tcx.map.expect_impl_item(impl_m_node_id).node { + ImplItemKind::Method(ref impl_m_sig, _) => { + (&impl_m_sig.decl.output, impl_m_sig.decl.inputs.iter()) + } + _ => bug!("{:?} is not a method", impl_m), + }; + + match *terr { + TypeError::Mutability => { + if let Some(trait_m_node_id) = tcx.map.as_local_node_id(trait_m.def_id) { + let trait_m_iter = match tcx.map.expect_trait_item(trait_m_node_id).node { + TraitItem_::MethodTraitItem(ref trait_m_sig, _) => { + trait_m_sig.decl.inputs.iter() + } + _ => bug!("{:?} is not a MethodTraitItem", trait_m), + }; + + impl_m_iter.zip(trait_m_iter) + .find(|&(ref impl_arg, ref trait_arg)| { + match (&impl_arg.ty.node, &trait_arg.ty.node) { + (&Ty_::TyRptr(_, ref impl_mt), &Ty_::TyRptr(_, ref trait_mt)) | + (&Ty_::TyPtr(ref impl_mt), &Ty_::TyPtr(ref trait_mt)) => { + impl_mt.mutbl != trait_mt.mutbl + } + _ => false, + } + }) + .map(|(ref impl_arg, ref trait_arg)| { + match (impl_arg.to_self(), trait_arg.to_self()) { + (Some(impl_self), Some(trait_self)) => { + (impl_self.span, Some(trait_self.span)) + } + (None, None) => (impl_arg.ty.span, Some(trait_arg.ty.span)), + _ => { + bug!("impl and trait fns have different first args, impl: \ + {:?}, trait: {:?}", + impl_arg, + trait_arg) + } + } + }) + .unwrap_or((origin.span(), tcx.map.span_if_local(trait_m.def_id))) + } else { + (origin.span(), tcx.map.span_if_local(trait_m.def_id)) + } + } + TypeError::Sorts(ExpectedFound { .. }) => { + if let Some(trait_m_node_id) = tcx.map.as_local_node_id(trait_m.def_id) { + let (trait_m_output, trait_m_iter) = + match tcx.map.expect_trait_item(trait_m_node_id).node { + TraitItem_::MethodTraitItem(ref trait_m_sig, _) => { + (&trait_m_sig.decl.output, trait_m_sig.decl.inputs.iter()) + } + _ => bug!("{:?} is not a MethodTraitItem", trait_m), }; - impl_m_iter.zip(trait_m_iter).find(|&(ref impl_arg, ref trait_arg)| { - match (&impl_arg.ty.node, &trait_arg.ty.node) { - (&Ty_::TyRptr(_, ref impl_mt), &Ty_::TyRptr(_, ref trait_mt)) | - (&Ty_::TyPtr(ref impl_mt), &Ty_::TyPtr(ref trait_mt)) => - impl_mt.mutbl != trait_mt.mutbl, - _ => false - } - }).map(|(ref impl_arg, ref trait_arg)| { - match (impl_arg.to_self(), trait_arg.to_self()) { - (Some(impl_self), Some(trait_self)) => - (impl_self.span, Some(trait_self.span)), - (None, None) => (impl_arg.ty.span, Some(trait_arg.ty.span)), - _ => bug!("impl and trait fns have different first args, \ - impl: {:?}, trait: {:?}", impl_arg, trait_arg) - } - }).unwrap_or((origin.span(), tcx.map.span_if_local(trait_m.def_id))) + let impl_iter = impl_sig.inputs.iter(); + let trait_iter = trait_sig.inputs.iter(); + impl_iter.zip(trait_iter) + .zip(impl_m_iter) + .zip(trait_m_iter) + .filter_map(|(((impl_arg_ty, trait_arg_ty), impl_arg), trait_arg)| { + match infcx.sub_types(true, origin, trait_arg_ty, impl_arg_ty) { + Ok(_) => None, + Err(_) => Some((impl_arg.ty.span, Some(trait_arg.ty.span))), + } + }) + .next() + .unwrap_or_else(|| { + if infcx.sub_types(false, origin, impl_sig.output, trait_sig.output) + .is_err() { + (impl_m_output.span(), Some(trait_m_output.span())) + } else { + (origin.span(), tcx.map.span_if_local(trait_m.def_id)) + } + }) + } else { + (origin.span(), tcx.map.span_if_local(trait_m.def_id)) + } + } + _ => (origin.span(), tcx.map.span_if_local(trait_m.def_id)), + } +} + +fn compare_self_type<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>, + impl_m: &ty::Method<'tcx>, + impl_m_span: Span, + trait_m: &ty::Method<'tcx>) + -> Result<(), ErrorReported> +{ + let tcx = ccx.tcx; + // Try to give more informative error messages about self typing + // mismatches. Note that any mismatch will also be detected + // below, where we construct a canonical function type that + // includes the self parameter as a normal parameter. It's just + // that the error messages you get out of this code are a bit more + // inscrutable, particularly for cases where one method has no + // self. + match (&trait_m.explicit_self, &impl_m.explicit_self) { + (&ty::ExplicitSelfCategory::Static, &ty::ExplicitSelfCategory::Static) => {} + (&ty::ExplicitSelfCategory::Static, _) => { + let mut err = struct_span_err!(tcx.sess, + impl_m_span, + E0185, + "method `{}` has a `{}` declaration in the impl, but \ + not in the trait", + trait_m.name, + impl_m.explicit_self); + err.span_label(impl_m_span, + &format!("`{}` used in impl", impl_m.explicit_self)); + if let Some(span) = tcx.map.span_if_local(trait_m.def_id) { + err.span_label(span, + &format!("trait declared without `{}`", impl_m.explicit_self)); + } + err.emit(); + return Err(ErrorReported); + } + (_, &ty::ExplicitSelfCategory::Static) => { + let mut err = struct_span_err!(tcx.sess, + impl_m_span, + E0186, + "method `{}` has a `{}` declaration in the trait, but \ + not in the impl", + trait_m.name, + trait_m.explicit_self); + err.span_label(impl_m_span, + &format!("expected `{}` in impl", trait_m.explicit_self)); + if let Some(span) = tcx.map.span_if_local(trait_m.def_id) { + err.span_label(span, &format!("`{}` used in trait", trait_m.explicit_self)); + } + err.emit(); + return Err(ErrorReported); + } + _ => { + // Let the type checker catch other errors below + } + } + + Ok(()) +} + +fn compare_number_of_generics<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>, + impl_m: &ty::Method<'tcx>, + impl_m_span: Span, + trait_m: &ty::Method<'tcx>, + trait_item_span: Option) + -> Result<(), ErrorReported> { + let tcx = ccx.tcx; + let num_impl_m_type_params = impl_m.generics.types.len(); + let num_trait_m_type_params = trait_m.generics.types.len(); + if num_impl_m_type_params != num_trait_m_type_params { + let impl_m_node_id = tcx.map.as_local_node_id(impl_m.def_id).unwrap(); + let span = match tcx.map.expect_impl_item(impl_m_node_id).node { + ImplItemKind::Method(ref impl_m_sig, _) => { + if impl_m_sig.generics.is_parameterized() { + impl_m_sig.generics.span } else { - (origin.span(), tcx.map.span_if_local(trait_m.def_id)) + impl_m_span } } - TypeError::Sorts(ExpectedFound { .. }) => { - if let Some(trait_m_node_id) = tcx.map.as_local_node_id(trait_m.def_id) { - let (trait_m_output, trait_m_iter) = - match tcx.map.expect_trait_item(trait_m_node_id).node { - TraitItem_::MethodTraitItem(ref trait_m_sig, _) => - (&trait_m_sig.decl.output, trait_m_sig.decl.inputs.iter()), - _ => bug!("{:?} is not a MethodTraitItem", trait_m) - }; + _ => bug!("{:?} is not a method", impl_m), + }; + + let mut err = struct_span_err!(tcx.sess, + span, + E0049, + "method `{}` has {} type parameter{} but its trait \ + declaration has {} type parameter{}", + trait_m.name, + num_impl_m_type_params, + if num_impl_m_type_params == 1 { "" } else { "s" }, + num_trait_m_type_params, + if num_trait_m_type_params == 1 { + "" + } else { + "s" + }); - let impl_iter = impl_sig.inputs.iter(); - let trait_iter = trait_sig.inputs.iter(); - impl_iter.zip(trait_iter).zip(impl_m_iter).zip(trait_m_iter) - .filter_map(|(((impl_arg_ty, trait_arg_ty), impl_arg), trait_arg)| { - match infcx.sub_types(true, origin, trait_arg_ty, impl_arg_ty) { - Ok(_) => None, - Err(_) => Some((impl_arg.ty.span, Some(trait_arg.ty.span))) - } - }) - .next() - .unwrap_or_else(|| { - if infcx.sub_types(false, origin, impl_sig.output, - trait_sig.output).is_err() { - (impl_m_output.span(), Some(trait_m_output.span())) - } else { - (origin.span(), tcx.map.span_if_local(trait_m.def_id)) - } - }) + let mut suffix = None; + + if let Some(span) = trait_item_span { + err.span_label(span, + &format!("expected {}", + &if num_trait_m_type_params != 1 { + format!("{} type parameters", num_trait_m_type_params) + } else { + format!("{} type parameter", num_trait_m_type_params) + })); + } else { + suffix = Some(format!(", expected {}", num_trait_m_type_params)); + } + + err.span_label(span, + &format!("found {}{}", + &if num_impl_m_type_params != 1 { + format!("{} type parameters", num_impl_m_type_params) + } else { + format!("1 type parameter") + }, + suffix.as_ref().map(|s| &s[..]).unwrap_or(""))); + + err.emit(); + + return Err(ErrorReported); + } + + Ok(()) +} + +fn compare_number_of_method_arguments<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>, + impl_m: &ty::Method<'tcx>, + impl_m_span: Span, + trait_m: &ty::Method<'tcx>, + trait_item_span: Option) + -> Result<(), ErrorReported> { + let tcx = ccx.tcx; + if impl_m.fty.sig.0.inputs.len() != trait_m.fty.sig.0.inputs.len() { + let trait_number_args = trait_m.fty.sig.0.inputs.len(); + let impl_number_args = impl_m.fty.sig.0.inputs.len(); + let trait_m_node_id = tcx.map.as_local_node_id(trait_m.def_id); + let trait_span = if let Some(trait_id) = trait_m_node_id { + match tcx.map.expect_trait_item(trait_id).node { + TraitItem_::MethodTraitItem(ref trait_m_sig, _) => { + if let Some(arg) = trait_m_sig.decl.inputs.get(if trait_number_args > 0 { + trait_number_args - 1 + } else { + 0 + }) { + Some(arg.pat.span) + } else { + trait_item_span + } + } + _ => bug!("{:?} is not a method", impl_m), + } + } else { + trait_item_span + }; + let impl_m_node_id = tcx.map.as_local_node_id(impl_m.def_id).unwrap(); + let impl_span = match tcx.map.expect_impl_item(impl_m_node_id).node { + ImplItemKind::Method(ref impl_m_sig, _) => { + if let Some(arg) = impl_m_sig.decl.inputs.get(if impl_number_args > 0 { + impl_number_args - 1 + } else { + 0 + }) { + arg.pat.span } else { - (origin.span(), tcx.map.span_if_local(trait_m.def_id)) + impl_m_span } } - _ => (origin.span(), tcx.map.span_if_local(trait_m.def_id)) + _ => bug!("{:?} is not a method", impl_m), + }; + let mut err = struct_span_err!(tcx.sess, + impl_span, + E0050, + "method `{}` has {} parameter{} but the declaration in \ + trait `{}` has {}", + trait_m.name, + impl_number_args, + if impl_number_args == 1 { "" } else { "s" }, + tcx.item_path_str(trait_m.def_id), + trait_number_args); + if let Some(trait_span) = trait_span { + err.span_label(trait_span, + &format!("trait requires {}", + &if trait_number_args != 1 { + format!("{} parameters", trait_number_args) + } else { + format!("{} parameter", trait_number_args) + })); } + err.span_label(impl_span, + &format!("expected {}, found {}", + &if trait_number_args != 1 { + format!("{} parameters", trait_number_args) + } else { + format!("{} parameter", trait_number_args) + }, + impl_number_args)); + err.emit(); + return Err(ErrorReported); } + + Ok(()) } pub fn compare_const_impl<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>, @@ -547,8 +712,7 @@ pub fn compare_const_impl<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>, impl_c_span: Span, trait_c: &ty::AssociatedConst<'tcx>, impl_trait_ref: &ty::TraitRef<'tcx>) { - debug!("compare_const_impl(impl_trait_ref={:?})", - impl_trait_ref); + debug!("compare_const_impl(impl_trait_ref={:?})", impl_trait_ref); let tcx = ccx.tcx; tcx.infer_ctxt(None, None, Reveal::NotSpecializable).enter(|infcx| { @@ -570,11 +734,12 @@ pub fn compare_const_impl<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>, let impl_to_skol_substs = &impl_param_env.free_substs; // Create mapping from trait to skolemized. - let trait_to_skol_substs = - impl_to_skol_substs.rebase_onto(tcx, impl_c.container.id(), - trait_to_impl_substs.subst(tcx, impl_to_skol_substs)); + let trait_to_skol_substs = impl_to_skol_substs.rebase_onto(tcx, + impl_c.container.id(), + trait_to_impl_substs.subst(tcx, + impl_to_skol_substs)); debug!("compare_const_impl: trait_to_skol_substs={:?}", - trait_to_skol_substs); + trait_to_skol_substs); // Compute skolemized form of impl and trait const tys. let impl_ty = impl_c.ty.subst(tcx, impl_to_skol_substs); @@ -583,31 +748,27 @@ pub fn compare_const_impl<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>, let err = infcx.commit_if_ok(|_| { // There is no "body" here, so just pass dummy id. - let impl_ty = - assoc::normalize_associated_types_in(&infcx, - &mut fulfillment_cx, - impl_c_span, - ast::CRATE_NODE_ID, - &impl_ty); - - debug!("compare_const_impl: impl_ty={:?}", - impl_ty); - - let trait_ty = - assoc::normalize_associated_types_in(&infcx, - &mut fulfillment_cx, - impl_c_span, - ast::CRATE_NODE_ID, - &trait_ty); - - debug!("compare_const_impl: trait_ty={:?}", - trait_ty); + let impl_ty = assoc::normalize_associated_types_in(&infcx, + &mut fulfillment_cx, + impl_c_span, + ast::CRATE_NODE_ID, + &impl_ty); + + debug!("compare_const_impl: impl_ty={:?}", impl_ty); + + let trait_ty = assoc::normalize_associated_types_in(&infcx, + &mut fulfillment_cx, + impl_c_span, + ast::CRATE_NODE_ID, + &trait_ty); + + debug!("compare_const_impl: trait_ty={:?}", trait_ty); infcx.sub_types(false, origin, impl_ty, trait_ty) - .map(|InferOk { obligations, .. }| { - // FIXME(#32730) propagate obligations - assert!(obligations.is_empty()) - }) + .map(|InferOk { obligations, .. }| { + // FIXME(#32730) propagate obligations + assert!(obligations.is_empty()) + }) }); if let Err(terr) = err { @@ -618,31 +779,31 @@ pub fn compare_const_impl<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>, // Locate the Span containing just the type of the offending impl match tcx.map.expect_impl_item(impl_c_node_id).node { ImplItemKind::Const(ref ty, _) => origin = TypeOrigin::Misc(ty.span), - _ => bug!("{:?} is not a impl const", impl_c) + _ => bug!("{:?} is not a impl const", impl_c), } - let mut diag = struct_span_err!( - tcx.sess, origin.span(), E0326, - "implemented const `{}` has an incompatible type for trait", - trait_c.name - ); + let mut diag = struct_span_err!(tcx.sess, + origin.span(), + E0326, + "implemented const `{}` has an incompatible type for \ + trait", + trait_c.name); // Add a label to the Span containing just the type of the item let trait_c_node_id = tcx.map.as_local_node_id(trait_c.def_id).unwrap(); let trait_c_span = match tcx.map.expect_trait_item(trait_c_node_id).node { TraitItem_::ConstTraitItem(ref ty, _) => ty.span, - _ => bug!("{:?} is not a trait const", trait_c) + _ => bug!("{:?} is not a trait const", trait_c), }; - infcx.note_type_err( - &mut diag, - origin, - Some((trait_c_span, format!("type in trait"))), - Some(infer::ValuePairs::Types(ExpectedFound { - expected: trait_ty, - found: impl_ty - })), &terr - ); + infcx.note_type_err(&mut diag, + origin, + Some((trait_c_span, format!("type in trait"))), + Some(infer::ValuePairs::Types(ExpectedFound { + expected: trait_ty, + found: impl_ty, + })), + &terr); diag.emit(); } }); diff --git a/src/librustc_typeck/check/dropck.rs b/src/librustc_typeck/check/dropck.rs index cc958fb3b2..e72bcb3079 100644 --- a/src/librustc_typeck/check/dropck.rs +++ b/src/librustc_typeck/check/dropck.rs @@ -13,7 +13,7 @@ use check::regionck::RegionCtxt; use hir::def_id::DefId; use middle::free_region::FreeRegionMap; -use rustc::infer; +use rustc::infer::{self, InferOk}; use middle::region; use rustc::ty::subst::{Subst, Substs}; use rustc::ty::{self, AdtKind, Ty, TyCtxt}; @@ -71,7 +71,8 @@ fn ensure_drop_params_and_item_params_correspond<'a, 'tcx>( ccx: &CrateCtxt<'a, 'tcx>, drop_impl_did: DefId, drop_impl_ty: Ty<'tcx>, - self_type_did: DefId) -> Result<(), ()> + self_type_did: DefId) + -> Result<(), ()> { let tcx = ccx.tcx; let drop_impl_node_id = tcx.map.as_local_node_id(drop_impl_did).unwrap(); @@ -92,16 +93,22 @@ fn ensure_drop_params_and_item_params_correspond<'a, 'tcx>( infcx.fresh_substs_for_item(drop_impl_span, drop_impl_did); let fresh_impl_self_ty = drop_impl_ty.subst(tcx, fresh_impl_substs); - if let Err(_) = infcx.eq_types(true, infer::TypeOrigin::Misc(drop_impl_span), - named_type, fresh_impl_self_ty) { - let item_span = tcx.map.span(self_type_node_id); - struct_span_err!(tcx.sess, drop_impl_span, E0366, - "Implementations of Drop cannot be specialized") - .span_note(item_span, - "Use same sequence of generic type and region \ - parameters that is on the struct/enum definition") - .emit(); - return Err(()); + match infcx.eq_types(true, infer::TypeOrigin::Misc(drop_impl_span), + named_type, fresh_impl_self_ty) { + Ok(InferOk { obligations, .. }) => { + // FIXME(#32730) propagate obligations + assert!(obligations.is_empty()); + } + Err(_) => { + let item_span = tcx.map.span(self_type_node_id); + struct_span_err!(tcx.sess, drop_impl_span, E0366, + "Implementations of Drop cannot be specialized") + .span_note(item_span, + "Use same sequence of generic type and region \ + parameters that is on the struct/enum definition") + .emit(); + return Err(()); + } } if let Err(ref errors) = fulfillment_cx.select_all_or_error(&infcx) { @@ -123,7 +130,9 @@ fn ensure_drop_predicates_are_implied_by_item_defn<'a, 'tcx>( drop_impl_did: DefId, dtor_predicates: &ty::GenericPredicates<'tcx>, self_type_did: DefId, - self_to_impl_substs: &Substs<'tcx>) -> Result<(), ()> { + self_to_impl_substs: &Substs<'tcx>) + -> Result<(), ()> +{ // Here is an example, analogous to that from // `compare_impl_method`. @@ -350,7 +359,8 @@ fn iterate_over_potentially_unsafe_regions_in_type<'a, 'b, 'gcx, 'tcx>( cx: &mut DropckContext<'a, 'b, 'gcx, 'tcx>, context: TypeContext, ty: Ty<'tcx>, - depth: usize) -> Result<(), Error<'tcx>> + depth: usize) + -> Result<(), Error<'tcx>> { let tcx = cx.rcx.tcx; // Issue #22443: Watch out for overflow. While we are careful to @@ -402,16 +412,27 @@ fn iterate_over_potentially_unsafe_regions_in_type<'a, 'b, 'gcx, 'tcx>( // unbounded type parameter `T`, we must resume the recursive // analysis on `T` (since it would be ignored by // type_must_outlive). - if has_dtor_of_interest(tcx, ty) { - debug!("iterate_over_potentially_unsafe_regions_in_type \ - {}ty: {} - is a dtorck type!", - (0..depth).map(|_| ' ').collect::(), - ty); - - cx.rcx.type_must_outlive(infer::SubregionOrigin::SafeDestructor(cx.span), - ty, tcx.mk_region(ty::ReScope(cx.parent_scope))); - - return Ok(()); + let dropck_kind = has_dtor_of_interest(tcx, ty); + debug!("iterate_over_potentially_unsafe_regions_in_type \ + ty: {:?} dropck_kind: {:?}", ty, dropck_kind); + match dropck_kind { + DropckKind::NoBorrowedDataAccessedInMyDtor => { + // The maximally blind attribute. + } + DropckKind::BorrowedDataMustStrictlyOutliveSelf => { + cx.rcx.type_must_outlive(infer::SubregionOrigin::SafeDestructor(cx.span), + ty, tcx.mk_region(ty::ReScope(cx.parent_scope))); + return Ok(()); + } + DropckKind::RevisedSelf(revised_ty) => { + cx.rcx.type_must_outlive(infer::SubregionOrigin::SafeDestructor(cx.span), + revised_ty, tcx.mk_region(ty::ReScope(cx.parent_scope))); + // Do not return early from this case; we want + // to recursively process the internal structure of Self + // (because even though the Drop for Self has been asserted + // safe, the types instantiated for the generics of Self + // may themselves carry dropck constraints.) + } } debug!("iterate_over_potentially_unsafe_regions_in_type \ @@ -492,16 +513,140 @@ fn iterate_over_potentially_unsafe_regions_in_type<'a, 'b, 'gcx, 'tcx>( } } +#[derive(Copy, Clone, PartialEq, Eq, Debug)] +enum DropckKind<'tcx> { + /// The "safe" kind; i.e. conservatively assume any borrow + /// accessed by dtor, and therefore such data must strictly + /// outlive self. + /// + /// Equivalent to RevisedTy with no change to the self type. + BorrowedDataMustStrictlyOutliveSelf, + + /// The nearly completely-unsafe kind. + /// + /// Equivalent to RevisedSelf with *all* parameters remapped to () + /// (maybe...?) + NoBorrowedDataAccessedInMyDtor, + + /// Assume all borrowed data access by dtor occurs as if Self has the + /// type carried by this variant. In practice this means that some + /// of the type parameters are remapped to `()` (and some lifetime + /// parameters remapped to `'static`), because the developer has asserted + /// that the destructor will not access their contents. + RevisedSelf(Ty<'tcx>), +} + +/// Returns the classification of what kind of check should be applied +/// to `ty`, which may include a revised type where some of the type +/// parameters are re-mapped to `()` to reflect the destructor's +/// "purity" with respect to their actual contents. fn has_dtor_of_interest<'a, 'gcx, 'tcx>(tcx: TyCtxt<'a, 'gcx, 'tcx>, - ty: Ty<'tcx>) -> bool { + ty: Ty<'tcx>) + -> DropckKind<'tcx> { match ty.sty { - ty::TyAdt(def, _) => { - def.is_dtorck(tcx) + ty::TyAdt(adt_def, substs) => { + if !adt_def.is_dtorck(tcx) { + return DropckKind::NoBorrowedDataAccessedInMyDtor; + } + + // Find the `impl<..> Drop for _` to inspect any + // attributes attached to the impl's generics. + let dtor_method = adt_def.destructor() + .expect("dtorck type without destructor impossible"); + let method = tcx.impl_or_trait_item(dtor_method); + let impl_id: DefId = method.container().id(); + let revised_ty = revise_self_ty(tcx, adt_def, impl_id, substs); + return DropckKind::RevisedSelf(revised_ty); } ty::TyTrait(..) | ty::TyProjection(..) | ty::TyAnon(..) => { debug!("ty: {:?} isn't known, and therefore is a dropck type", ty); - true + return DropckKind::BorrowedDataMustStrictlyOutliveSelf; }, - _ => false + _ => { + return DropckKind::NoBorrowedDataAccessedInMyDtor; + } } } + +// Constructs new Ty just like the type defined by `adt_def` coupled +// with `substs`, except each type and lifetime parameter marked as +// `#[may_dangle]` in the Drop impl (identified by `impl_id`) is +// respectively mapped to `()` or `'static`. +// +// For example: If the `adt_def` maps to: +// +// enum Foo<'a, X, Y> { ... } +// +// and the `impl_id` maps to: +// +// impl<#[may_dangle] 'a, X, #[may_dangle] Y> Drop for Foo<'a, X, Y> { ... } +// +// then revises input: `Foo<'r,i64,&'r i64>` to: `Foo<'static,i64,()>` +fn revise_self_ty<'a, 'gcx, 'tcx>(tcx: TyCtxt<'a, 'gcx, 'tcx>, + adt_def: ty::AdtDef<'tcx>, + impl_id: DefId, + substs: &Substs<'tcx>) + -> Ty<'tcx> { + // Get generics for `impl Drop` to query for `#[may_dangle]` attr. + let impl_bindings = tcx.lookup_generics(impl_id); + + // Get Substs attached to Self on `impl Drop`; process in parallel + // with `substs`, replacing dangling entries as appropriate. + let self_substs = { + let impl_self_ty: Ty<'tcx> = tcx.lookup_item_type(impl_id).ty; + if let ty::TyAdt(self_adt_def, self_substs) = impl_self_ty.sty { + assert_eq!(adt_def, self_adt_def); + self_substs + } else { + bug!("Self in `impl Drop for _` must be an Adt."); + } + }; + + // Walk `substs` + `self_substs`, build new substs appropriate for + // `adt_def`; each non-dangling param reuses entry from `substs`. + // + // Note: The manner we map from a right-hand side (i.e. Region or + // Ty) for a given `def` to generic parameter associated with that + // right-hand side is tightly coupled to `Drop` impl constraints. + // + // E.g. we know such a Ty must be `TyParam`, because a destructor + // for `struct Foo` is defined via `impl Drop for Foo`, + // and never by (for example) `impl Drop for Foo>`. + let substs = Substs::for_item( + tcx, + adt_def.did, + |def, _| { + let r_orig = substs.region_for_def(def); + let impl_self_orig = self_substs.region_for_def(def); + let r = if let ty::Region::ReEarlyBound(ref ebr) = *impl_self_orig { + if impl_bindings.region_param(ebr).pure_wrt_drop { + tcx.mk_region(ty::ReStatic) + } else { + r_orig + } + } else { + bug!("substs for an impl must map regions to ReEarlyBound"); + }; + debug!("has_dtor_of_interest mapping def {:?} orig {:?} to {:?}", + def, r_orig, r); + r + }, + |def, _| { + let t_orig = substs.type_for_def(def); + let impl_self_orig = self_substs.type_for_def(def); + let t = if let ty::TypeVariants::TyParam(ref pt) = impl_self_orig.sty { + if impl_bindings.type_param(pt).pure_wrt_drop { + tcx.mk_nil() + } else { + t_orig + } + } else { + bug!("substs for an impl must map types to TyParam"); + }; + debug!("has_dtor_of_interest mapping def {:?} orig {:?} {:?} to {:?} {:?}", + def, t_orig, t_orig.sty, t, t.sty); + t + }); + + return tcx.mk_adt(adt_def, &substs); +} diff --git a/src/librustc_typeck/check/intrinsic.rs b/src/librustc_typeck/check/intrinsic.rs index 93d8b3e156..7d2547ec17 100644 --- a/src/librustc_typeck/check/intrinsic.rs +++ b/src/librustc_typeck/check/intrinsic.rs @@ -86,18 +86,18 @@ pub fn check_intrinsic_type(ccx: &CrateCtxt, it: &hir::ForeignItem) { //We only care about the operation here let (n_tps, inputs, output) = match split[1] { - "cxchg" | "cxchgweak" => (1, vec!(tcx.mk_mut_ptr(param(ccx, 0)), + "cxchg" | "cxchgweak" => (1, vec![tcx.mk_mut_ptr(param(ccx, 0)), param(ccx, 0), - param(ccx, 0)), - tcx.mk_tup(vec!(param(ccx, 0), tcx.types.bool))), - "load" => (1, vec!(tcx.mk_imm_ptr(param(ccx, 0))), + param(ccx, 0)], + tcx.intern_tup(&[param(ccx, 0), tcx.types.bool])), + "load" => (1, vec![tcx.mk_imm_ptr(param(ccx, 0))], param(ccx, 0)), - "store" => (1, vec!(tcx.mk_mut_ptr(param(ccx, 0)), param(ccx, 0)), + "store" => (1, vec![tcx.mk_mut_ptr(param(ccx, 0)), param(ccx, 0)], tcx.mk_nil()), "xchg" | "xadd" | "xsub" | "and" | "nand" | "or" | "xor" | "max" | "min" | "umax" | "umin" => { - (1, vec!(tcx.mk_mut_ptr(param(ccx, 0)), param(ccx, 0)), + (1, vec![tcx.mk_mut_ptr(param(ccx, 0)), param(ccx, 0)], param(ccx, 0)) } "fence" | "singlethreadfence" => { @@ -129,14 +129,14 @@ pub fn check_intrinsic_type(ccx: &CrateCtxt, it: &hir::ForeignItem) { "rustc_peek" => (1, vec![param(ccx, 0)], param(ccx, 0)), "init" => (1, Vec::new(), param(ccx, 0)), "uninit" => (1, Vec::new(), param(ccx, 0)), - "forget" => (1, vec!( param(ccx, 0) ), tcx.mk_nil()), - "transmute" => (2, vec!( param(ccx, 0) ), param(ccx, 1)), + "forget" => (1, vec![ param(ccx, 0) ], tcx.mk_nil()), + "transmute" => (2, vec![ param(ccx, 0) ], param(ccx, 1)), "move_val_init" => { (1, - vec!( + vec![ tcx.mk_mut_ptr(param(ccx, 0)), param(ccx, 0) - ), + ], tcx.mk_nil()) } "drop_in_place" => { @@ -148,13 +148,13 @@ pub fn check_intrinsic_type(ccx: &CrateCtxt, it: &hir::ForeignItem) { "type_id" => (1, Vec::new(), ccx.tcx.types.u64), "offset" | "arith_offset" => { (1, - vec!( + vec![ tcx.mk_ptr(ty::TypeAndMut { ty: param(ccx, 0), mutbl: hir::MutImmutable }), ccx.tcx.types.isize - ), + ], tcx.mk_ptr(ty::TypeAndMut { ty: param(ccx, 0), mutbl: hir::MutImmutable @@ -162,7 +162,7 @@ pub fn check_intrinsic_type(ccx: &CrateCtxt, it: &hir::ForeignItem) { } "copy" | "copy_nonoverlapping" => { (1, - vec!( + vec![ tcx.mk_ptr(ty::TypeAndMut { ty: param(ccx, 0), mutbl: hir::MutImmutable @@ -172,12 +172,12 @@ pub fn check_intrinsic_type(ccx: &CrateCtxt, it: &hir::ForeignItem) { mutbl: hir::MutMutable }), tcx.types.usize, - ), + ], tcx.mk_nil()) } "volatile_copy_memory" | "volatile_copy_nonoverlapping_memory" => { (1, - vec!( + vec![ tcx.mk_ptr(ty::TypeAndMut { ty: param(ccx, 0), mutbl: hir::MutMutable @@ -187,94 +187,94 @@ pub fn check_intrinsic_type(ccx: &CrateCtxt, it: &hir::ForeignItem) { mutbl: hir::MutImmutable }), tcx.types.usize, - ), + ], tcx.mk_nil()) } "write_bytes" | "volatile_set_memory" => { (1, - vec!( + vec![ tcx.mk_ptr(ty::TypeAndMut { ty: param(ccx, 0), mutbl: hir::MutMutable }), tcx.types.u8, tcx.types.usize, - ), + ], tcx.mk_nil()) } - "sqrtf32" => (0, vec!( tcx.types.f32 ), tcx.types.f32), - "sqrtf64" => (0, vec!( tcx.types.f64 ), tcx.types.f64), + "sqrtf32" => (0, vec![ tcx.types.f32 ], tcx.types.f32), + "sqrtf64" => (0, vec![ tcx.types.f64 ], tcx.types.f64), "powif32" => { (0, - vec!( tcx.types.f32, tcx.types.i32 ), + vec![ tcx.types.f32, tcx.types.i32 ], tcx.types.f32) } "powif64" => { (0, - vec!( tcx.types.f64, tcx.types.i32 ), + vec![ tcx.types.f64, tcx.types.i32 ], tcx.types.f64) } - "sinf32" => (0, vec!( tcx.types.f32 ), tcx.types.f32), - "sinf64" => (0, vec!( tcx.types.f64 ), tcx.types.f64), - "cosf32" => (0, vec!( tcx.types.f32 ), tcx.types.f32), - "cosf64" => (0, vec!( tcx.types.f64 ), tcx.types.f64), + "sinf32" => (0, vec![ tcx.types.f32 ], tcx.types.f32), + "sinf64" => (0, vec![ tcx.types.f64 ], tcx.types.f64), + "cosf32" => (0, vec![ tcx.types.f32 ], tcx.types.f32), + "cosf64" => (0, vec![ tcx.types.f64 ], tcx.types.f64), "powf32" => { (0, - vec!( tcx.types.f32, tcx.types.f32 ), + vec![ tcx.types.f32, tcx.types.f32 ], tcx.types.f32) } "powf64" => { (0, - vec!( tcx.types.f64, tcx.types.f64 ), + vec![ tcx.types.f64, tcx.types.f64 ], tcx.types.f64) } - "expf32" => (0, vec!( tcx.types.f32 ), tcx.types.f32), - "expf64" => (0, vec!( tcx.types.f64 ), tcx.types.f64), - "exp2f32" => (0, vec!( tcx.types.f32 ), tcx.types.f32), - "exp2f64" => (0, vec!( tcx.types.f64 ), tcx.types.f64), - "logf32" => (0, vec!( tcx.types.f32 ), tcx.types.f32), - "logf64" => (0, vec!( tcx.types.f64 ), tcx.types.f64), - "log10f32" => (0, vec!( tcx.types.f32 ), tcx.types.f32), - "log10f64" => (0, vec!( tcx.types.f64 ), tcx.types.f64), - "log2f32" => (0, vec!( tcx.types.f32 ), tcx.types.f32), - "log2f64" => (0, vec!( tcx.types.f64 ), tcx.types.f64), + "expf32" => (0, vec![ tcx.types.f32 ], tcx.types.f32), + "expf64" => (0, vec![ tcx.types.f64 ], tcx.types.f64), + "exp2f32" => (0, vec![ tcx.types.f32 ], tcx.types.f32), + "exp2f64" => (0, vec![ tcx.types.f64 ], tcx.types.f64), + "logf32" => (0, vec![ tcx.types.f32 ], tcx.types.f32), + "logf64" => (0, vec![ tcx.types.f64 ], tcx.types.f64), + "log10f32" => (0, vec![ tcx.types.f32 ], tcx.types.f32), + "log10f64" => (0, vec![ tcx.types.f64 ], tcx.types.f64), + "log2f32" => (0, vec![ tcx.types.f32 ], tcx.types.f32), + "log2f64" => (0, vec![ tcx.types.f64 ], tcx.types.f64), "fmaf32" => { (0, - vec!( tcx.types.f32, tcx.types.f32, tcx.types.f32 ), + vec![ tcx.types.f32, tcx.types.f32, tcx.types.f32 ], tcx.types.f32) } "fmaf64" => { (0, - vec!( tcx.types.f64, tcx.types.f64, tcx.types.f64 ), + vec![ tcx.types.f64, tcx.types.f64, tcx.types.f64 ], tcx.types.f64) } - "fabsf32" => (0, vec!( tcx.types.f32 ), tcx.types.f32), - "fabsf64" => (0, vec!( tcx.types.f64 ), tcx.types.f64), - "copysignf32" => (0, vec!( tcx.types.f32, tcx.types.f32 ), tcx.types.f32), - "copysignf64" => (0, vec!( tcx.types.f64, tcx.types.f64 ), tcx.types.f64), - "floorf32" => (0, vec!( tcx.types.f32 ), tcx.types.f32), - "floorf64" => (0, vec!( tcx.types.f64 ), tcx.types.f64), - "ceilf32" => (0, vec!( tcx.types.f32 ), tcx.types.f32), - "ceilf64" => (0, vec!( tcx.types.f64 ), tcx.types.f64), - "truncf32" => (0, vec!( tcx.types.f32 ), tcx.types.f32), - "truncf64" => (0, vec!( tcx.types.f64 ), tcx.types.f64), - "rintf32" => (0, vec!( tcx.types.f32 ), tcx.types.f32), - "rintf64" => (0, vec!( tcx.types.f64 ), tcx.types.f64), - "nearbyintf32" => (0, vec!( tcx.types.f32 ), tcx.types.f32), - "nearbyintf64" => (0, vec!( tcx.types.f64 ), tcx.types.f64), - "roundf32" => (0, vec!( tcx.types.f32 ), tcx.types.f32), - "roundf64" => (0, vec!( tcx.types.f64 ), tcx.types.f64), + "fabsf32" => (0, vec![ tcx.types.f32 ], tcx.types.f32), + "fabsf64" => (0, vec![ tcx.types.f64 ], tcx.types.f64), + "copysignf32" => (0, vec![ tcx.types.f32, tcx.types.f32 ], tcx.types.f32), + "copysignf64" => (0, vec![ tcx.types.f64, tcx.types.f64 ], tcx.types.f64), + "floorf32" => (0, vec![ tcx.types.f32 ], tcx.types.f32), + "floorf64" => (0, vec![ tcx.types.f64 ], tcx.types.f64), + "ceilf32" => (0, vec![ tcx.types.f32 ], tcx.types.f32), + "ceilf64" => (0, vec![ tcx.types.f64 ], tcx.types.f64), + "truncf32" => (0, vec![ tcx.types.f32 ], tcx.types.f32), + "truncf64" => (0, vec![ tcx.types.f64 ], tcx.types.f64), + "rintf32" => (0, vec![ tcx.types.f32 ], tcx.types.f32), + "rintf64" => (0, vec![ tcx.types.f64 ], tcx.types.f64), + "nearbyintf32" => (0, vec![ tcx.types.f32 ], tcx.types.f32), + "nearbyintf64" => (0, vec![ tcx.types.f64 ], tcx.types.f64), + "roundf32" => (0, vec![ tcx.types.f32 ], tcx.types.f32), + "roundf64" => (0, vec![ tcx.types.f64 ], tcx.types.f64), "volatile_load" => - (1, vec!( tcx.mk_imm_ptr(param(ccx, 0)) ), param(ccx, 0)), + (1, vec![ tcx.mk_imm_ptr(param(ccx, 0)) ], param(ccx, 0)), "volatile_store" => - (1, vec!( tcx.mk_mut_ptr(param(ccx, 0)), param(ccx, 0) ), tcx.mk_nil()), + (1, vec![ tcx.mk_mut_ptr(param(ccx, 0)), param(ccx, 0) ], tcx.mk_nil()), - "ctpop" | "ctlz" | "cttz" | "bswap" => (1, vec!(param(ccx, 0)), param(ccx, 0)), + "ctpop" | "ctlz" | "cttz" | "bswap" => (1, vec![param(ccx, 0)], param(ccx, 0)), "add_with_overflow" | "sub_with_overflow" | "mul_with_overflow" => - (1, vec!(param(ccx, 0), param(ccx, 0)), - tcx.mk_tup(vec!(param(ccx, 0), tcx.types.bool))), + (1, vec![param(ccx, 0), param(ccx, 0)], + tcx.intern_tup(&[param(ccx, 0), tcx.types.bool])), "unchecked_div" | "unchecked_rem" => (1, vec![param(ccx, 0), param(ccx, 0)], param(ccx, 0)), diff --git a/src/librustc_typeck/check/method/confirm.rs b/src/librustc_typeck/check/method/confirm.rs index ab59fafb65..f88bb355d1 100644 --- a/src/librustc_typeck/check/method/confirm.rs +++ b/src/librustc_typeck/check/method/confirm.rs @@ -15,7 +15,7 @@ use hir::def_id::DefId; use rustc::ty::subst::Substs; use rustc::traits; use rustc::ty::{self, LvaluePreference, NoPreference, PreferMutLvalue, Ty}; -use rustc::ty::adjustment::{AdjustDerefRef, AutoDerefRef, AutoPtr}; +use rustc::ty::adjustment::{Adjustment, Adjust, AutoBorrow}; use rustc::ty::fold::TypeFoldable; use rustc::infer::{self, InferOk, TypeOrigin}; use syntax_pos::Span; @@ -23,7 +23,7 @@ use rustc::hir; use std::ops::Deref; -struct ConfirmContext<'a, 'gcx: 'a+'tcx, 'tcx: 'a>{ +struct ConfirmContext<'a, 'gcx: 'a + 'tcx, 'tcx: 'a> { fcx: &'a FnCtxt<'a, 'gcx, 'tcx>, span: Span, self_expr: &'gcx hir::Expr, @@ -55,8 +55,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { unadjusted_self_ty: Ty<'tcx>, pick: probe::Pick<'tcx>, supplied_method_types: Vec>) - -> ty::MethodCallee<'tcx> - { + -> ty::MethodCallee<'tcx> { debug!("confirm(unadjusted_self_ty={:?}, pick={:?}, supplied_method_types={:?})", unadjusted_self_ty, pick, @@ -72,17 +71,20 @@ impl<'a, 'gcx, 'tcx> ConfirmContext<'a, 'gcx, 'tcx> { span: Span, self_expr: &'gcx hir::Expr, call_expr: &'gcx hir::Expr) - -> ConfirmContext<'a, 'gcx, 'tcx> - { - ConfirmContext { fcx: fcx, span: span, self_expr: self_expr, call_expr: call_expr } + -> ConfirmContext<'a, 'gcx, 'tcx> { + ConfirmContext { + fcx: fcx, + span: span, + self_expr: self_expr, + call_expr: call_expr, + } } fn confirm(&mut self, unadjusted_self_ty: Ty<'tcx>, pick: probe::Pick<'tcx>, supplied_method_types: Vec>) - -> ty::MethodCallee<'tcx> - { + -> ty::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); @@ -91,18 +93,13 @@ impl<'a, 'gcx, 'tcx> ConfirmContext<'a, 'gcx, 'tcx> { // Create substitutions for the method's type parameters. let rcvr_substs = self.fresh_receiver_substs(self_ty, &pick); - let all_substs = - self.instantiate_method_substs( - &pick, - supplied_method_types, - rcvr_substs); + let all_substs = self.instantiate_method_substs(&pick, supplied_method_types, rcvr_substs); debug!("all_substs={:?}", all_substs); // Create the final signature for the method, replacing late-bound regions. - let InstantiatedMethodSig { - method_sig, method_predicates - } = self.instantiate_method_sig(&pick, all_substs); + let InstantiatedMethodSig { method_sig, method_predicates } = + self.instantiate_method_sig(&pick, all_substs); let method_self_ty = method_sig.inputs[0]; // Unify the (adjusted) self type with what the method expects. @@ -111,12 +108,13 @@ impl<'a, 'gcx, 'tcx> ConfirmContext<'a, 'gcx, 'tcx> { // Create the method type let def_id = pick.item.def_id(); let method_ty = pick.item.as_opt_method().unwrap(); - let fty = self.tcx.mk_fn_def(def_id, all_substs, + let fty = self.tcx.mk_fn_def(def_id, + all_substs, self.tcx.mk_bare_fn(ty::BareFnTy { - sig: ty::Binder(method_sig), - unsafety: method_ty.fty.unsafety, - abi: method_ty.fty.abi.clone(), - })); + sig: ty::Binder(method_sig), + unsafety: method_ty.fty.unsafety, + abi: method_ty.fty.abi.clone(), + })); // Add any trait/regions obligations specified on the method's type parameters. self.add_obligations(fty, all_substs, &method_predicates); @@ -125,7 +123,7 @@ impl<'a, 'gcx, 'tcx> ConfirmContext<'a, 'gcx, 'tcx> { let callee = ty::MethodCallee { def_id: def_id, ty: fty, - substs: all_substs + substs: all_substs, }; if let Some(hir::MutMutable) = pick.autoref { @@ -141,23 +139,20 @@ impl<'a, 'gcx, 'tcx> ConfirmContext<'a, 'gcx, 'tcx> { fn adjust_self_ty(&mut self, unadjusted_self_ty: Ty<'tcx>, pick: &probe::Pick<'tcx>) - -> Ty<'tcx> - { - let (autoref, unsize) = if let Some(mutbl) = pick.autoref { + -> Ty<'tcx> { + let autoref = if let Some(mutbl) = pick.autoref { let region = self.next_region_var(infer::Autoref(self.span)); - let autoref = AutoPtr(region, mutbl); - (Some(autoref), pick.unsize.map(|target| { - target.adjust_for_autoref(self.tcx, Some(autoref)) - })) + Some(AutoBorrow::Ref(region, mutbl)) } 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) + None }; + // Commit the autoderefs by calling `autoderef` again, but this // time writing the results into the various tables. let mut autoderef = self.autoderef(self.span, unadjusted_self_ty); @@ -167,18 +162,20 @@ impl<'a, 'gcx, 'tcx> ConfirmContext<'a, 'gcx, 'tcx> { autoderef.unambiguous_final_ty(); autoderef.finalize(LvaluePreference::NoPreference, Some(self.self_expr)); + let target = pick.unsize.unwrap_or(autoderefd_ty); + let target = target.adjust_for_autoref(self.tcx, autoref); + // Write out the final adjustment. - self.write_adjustment(self.self_expr.id, AdjustDerefRef(AutoDerefRef { - autoderefs: pick.autoderefs, - autoref: autoref, - unsize: unsize - })); - - if let Some(target) = unsize { - target - } else { - autoderefd_ty.adjust_for_autoref(self.tcx, autoref) - } + self.write_adjustment(self.self_expr.id, Adjustment { + kind: Adjust::DerefRef { + autoderefs: pick.autoderefs, + autoref: autoref, + unsize: pick.unsize.is_some(), + }, + target: target + }); + + target } /////////////////////////////////////////////////////////////////////////// @@ -193,13 +190,13 @@ impl<'a, 'gcx, 'tcx> ConfirmContext<'a, 'gcx, 'tcx> { fn fresh_receiver_substs(&mut self, self_ty: Ty<'tcx>, pick: &probe::Pick<'tcx>) - -> &'tcx Substs<'tcx> - { + -> &'tcx Substs<'tcx> { match pick.kind { probe::InherentImplPick => { let impl_def_id = pick.item.container().id(); assert!(self.tcx.impl_trait_ref(impl_def_id).is_none(), - "impl {:?} is not an inherent impl", impl_def_id); + "impl {:?} is not an inherent impl", + impl_def_id); self.impl_self_ty(self.span, impl_def_id).substs } @@ -216,10 +213,8 @@ impl<'a, 'gcx, 'tcx> ConfirmContext<'a, 'gcx, 'tcx> { // argument type), but those cases have already // been ruled out when we deemed the trait to be // "object safe". - let original_poly_trait_ref = - principal.with_self_ty(this.tcx, object_ty); - let upcast_poly_trait_ref = - this.upcast(original_poly_trait_ref, trait_def_id); + let original_poly_trait_ref = principal.with_self_ty(this.tcx, object_ty); + let upcast_poly_trait_ref = this.upcast(original_poly_trait_ref, trait_def_id); let upcast_trait_ref = this.replace_late_bound_regions_with_fresh_var(&upcast_poly_trait_ref); debug!("original_poly_trait_ref={:?} upcast_trait_ref={:?} target_trait={:?}", @@ -242,10 +237,9 @@ impl<'a, 'gcx, 'tcx> ConfirmContext<'a, 'gcx, 'tcx> { // the impl ([$A,$B,$C]) not the receiver type ([$C]). let impl_polytype = self.impl_self_ty(self.span, impl_def_id); let impl_trait_ref = - self.instantiate_type_scheme( - self.span, - impl_polytype.substs, - &self.tcx.impl_trait_ref(impl_def_id).unwrap()); + self.instantiate_type_scheme(self.span, + impl_polytype.substs, + &self.tcx.impl_trait_ref(impl_def_id).unwrap()); impl_trait_ref.substs } @@ -268,12 +262,11 @@ impl<'a, 'gcx, 'tcx> ConfirmContext<'a, 'gcx, 'tcx> { } } - fn extract_existential_trait_ref(&mut self, - self_ty: Ty<'tcx>, - mut closure: F) -> R + fn extract_existential_trait_ref(&mut self, self_ty: Ty<'tcx>, mut closure: F) -> R where F: FnMut(&mut ConfirmContext<'a, 'gcx, 'tcx>, Ty<'tcx>, - ty::PolyExistentialTraitRef<'tcx>) -> R, + ty::PolyExistentialTraitRef<'tcx>) + -> R { // If we specified that this is an object method, then the // self-type ought to be something that can be dereferenced to @@ -281,7 +274,8 @@ impl<'a, 'gcx, 'tcx> ConfirmContext<'a, 'gcx, 'tcx> { // etc). // FIXME: this feels, like, super dubious - self.fcx.autoderef(self.span, self_ty) + self.fcx + .autoderef(self.span, self_ty) .filter_map(|(ty, _)| { match ty.sty { ty::TyTrait(ref data) => Some(closure(self, ty, data.principal)), @@ -290,10 +284,9 @@ impl<'a, 'gcx, 'tcx> ConfirmContext<'a, 'gcx, 'tcx> { }) .next() .unwrap_or_else(|| { - span_bug!( - self.span, - "self-type `{}` for ObjectPick never dereferenced to an object", - self_ty) + span_bug!(self.span, + "self-type `{}` for ObjectPick never dereferenced to an object", + self_ty) }) } @@ -301,8 +294,7 @@ impl<'a, 'gcx, 'tcx> ConfirmContext<'a, 'gcx, 'tcx> { pick: &probe::Pick<'tcx>, mut supplied_method_types: Vec>, substs: &Substs<'tcx>) - -> &'tcx Substs<'tcx> - { + -> &'tcx Substs<'tcx> { // Determine the values for the generic parameters of the method. // If they were not explicitly supplied, just construct fresh // variables. @@ -312,13 +304,26 @@ impl<'a, 'gcx, 'tcx> ConfirmContext<'a, 'gcx, 'tcx> { if num_supplied_types > 0 && num_supplied_types != num_method_types { if num_method_types == 0 { - span_err!(self.tcx.sess, self.span, E0035, - "does not take type parameters"); + struct_span_err!(self.tcx.sess, + self.span, + E0035, + "does not take type parameters") + .span_label(self.span, &"called with unneeded type parameters") + .emit(); } else { - span_err!(self.tcx.sess, self.span, E0036, - "incorrect number of type parameters given for this method: \ - expected {}, found {}", - num_method_types, num_supplied_types); + struct_span_err!(self.tcx.sess, + self.span, + E0036, + "incorrect number of type parameters given for this method: \ + expected {}, found {}", + num_method_types, + num_supplied_types) + .span_label(self.span, + &format!("Passed {} type argument{}, expected {}", + num_supplied_types, + if num_supplied_types != 1 { "s" } else { "" }, + num_method_types)) + .emit(); } supplied_method_types = vec![self.tcx.types.err; num_method_types]; } @@ -328,14 +333,17 @@ impl<'a, 'gcx, 'tcx> ConfirmContext<'a, 'gcx, 'tcx> { // // FIXME -- permit users to manually specify lifetimes let supplied_start = substs.params().len() + method.generics.regions.len(); - Substs::for_item(self.tcx, method.def_id, |def, _| { + Substs::for_item(self.tcx, + method.def_id, + |def, _| { let i = def.index as usize; if i < substs.params().len() { substs.region_at(i) } else { self.region_var_for_def(self.span, def) } - }, |def, cur_substs| { + }, + |def, cur_substs| { let i = def.index as usize; if i < substs.params().len() { substs.type_at(i) @@ -347,21 +355,17 @@ impl<'a, 'gcx, 'tcx> ConfirmContext<'a, 'gcx, 'tcx> { }) } - fn unify_receivers(&mut self, - self_ty: Ty<'tcx>, - method_self_ty: Ty<'tcx>) - { - match self.sub_types(false, TypeOrigin::Misc(self.span), - self_ty, method_self_ty) { + fn unify_receivers(&mut self, self_ty: Ty<'tcx>, method_self_ty: Ty<'tcx>) { + match self.sub_types(false, TypeOrigin::Misc(self.span), self_ty, method_self_ty) { Ok(InferOk { obligations, .. }) => { // FIXME(#32730) propagate obligations assert!(obligations.is_empty()); } Err(_) => { - span_bug!( - self.span, - "{} was a subtype of {} but now is not?", - self_ty, method_self_ty); + span_bug!(self.span, + "{} was a subtype of {} but now is not?", + self_ty, + method_self_ty); } } } @@ -372,8 +376,7 @@ impl<'a, 'gcx, 'tcx> ConfirmContext<'a, 'gcx, 'tcx> { fn instantiate_method_sig(&mut self, pick: &probe::Pick<'tcx>, all_substs: &'tcx Substs<'tcx>) - -> InstantiatedMethodSig<'tcx> - { + -> InstantiatedMethodSig<'tcx> { debug!("instantiate_method_sig(pick={:?}, all_substs={:?})", pick, all_substs); @@ -381,13 +384,14 @@ impl<'a, 'gcx, 'tcx> ConfirmContext<'a, 'gcx, 'tcx> { // Instantiate the bounds on the method with the // type/early-bound-regions substitutions performed. There can // be no late-bound regions appearing here. - let method_predicates = pick.item.as_opt_method().unwrap() - .predicates.instantiate(self.tcx, all_substs); - let method_predicates = self.normalize_associated_types_in(self.span, - &method_predicates); + let method_predicates = pick.item + .as_opt_method() + .unwrap() + .predicates + .instantiate(self.tcx, all_substs); + let method_predicates = self.normalize_associated_types_in(self.span, &method_predicates); - debug!("method_predicates after subst = {:?}", - method_predicates); + debug!("method_predicates after subst = {:?}", method_predicates); // Instantiate late-bound regions and substitute the trait // parameters into the method type to get the actual method type. @@ -395,14 +399,16 @@ impl<'a, 'gcx, 'tcx> ConfirmContext<'a, 'gcx, 'tcx> { // NB: Instantiate late-bound regions first so that // `instantiate_type_scheme` can normalize associated types that // may reference those regions. - let method_sig = self.replace_late_bound_regions_with_fresh_var( - &pick.item.as_opt_method().unwrap().fty.sig); + let method_sig = self.replace_late_bound_regions_with_fresh_var(&pick.item + .as_opt_method() + .unwrap() + .fty + .sig); debug!("late-bound lifetimes from method instantiated, method_sig={:?}", method_sig); let method_sig = self.instantiate_type_scheme(self.span, all_substs, &method_sig); - debug!("type scheme substituted, method_sig={:?}", - method_sig); + debug!("type scheme substituted, method_sig={:?}", method_sig); InstantiatedMethodSig { method_sig: method_sig, @@ -419,9 +425,8 @@ impl<'a, 'gcx, 'tcx> ConfirmContext<'a, 'gcx, 'tcx> { all_substs, method_predicates); - self.add_obligations_for_parameters( - traits::ObligationCause::misc(self.span, self.body_id), - method_predicates); + self.add_obligations_for_parameters(traits::ObligationCause::misc(self.span, self.body_id), + method_predicates); // this is a projection from a trait reference, so we have to // make sure that the trait reference inputs are well-formed. @@ -458,26 +463,23 @@ impl<'a, 'gcx, 'tcx> ConfirmContext<'a, 'gcx, 'tcx> { // Fix up autoderefs and derefs. for (i, &expr) in exprs.iter().rev().enumerate() { + debug!("convert_lvalue_derefs_to_mutable: i={} expr={:?}", i, expr); + // Count autoderefs. - let autoderef_count = match self.tables - .borrow() - .adjustments - .get(&expr.id) { - Some(&AdjustDerefRef(ref adj)) => adj.autoderefs, - Some(_) | None => 0, - }; - - debug!("convert_lvalue_derefs_to_mutable: i={} expr={:?} \ - autoderef_count={}", - i, expr, autoderef_count); - - if autoderef_count > 0 { - let mut autoderef = self.autoderef(expr.span, self.node_ty(expr.id)); - autoderef.nth(autoderef_count).unwrap_or_else(|| { - span_bug!(expr.span, "expr was deref-able {} times but now isn't?", - autoderef_count); - }); - autoderef.finalize(PreferMutLvalue, Some(expr)); + let adjustment = self.tables.borrow().adjustments.get(&expr.id).cloned(); + match adjustment { + Some(Adjustment { kind: Adjust::DerefRef { autoderefs, .. }, .. }) => { + if autoderefs > 0 { + let mut autoderef = self.autoderef(expr.span, self.node_ty(expr.id)); + autoderef.nth(autoderefs).unwrap_or_else(|| { + span_bug!(expr.span, + "expr was deref-able {} times but now isn't?", + autoderefs); + }); + autoderef.finalize(PreferMutLvalue, Some(expr)); + } + } + Some(_) | None => {} } // Don't retry the first one or we might infinite loop! @@ -495,54 +497,65 @@ impl<'a, 'gcx, 'tcx> ConfirmContext<'a, 'gcx, 'tcx> { // ought to recode this routine so it doesn't // (ab)use the normal type checking paths. let adj = self.tables.borrow().adjustments.get(&base_expr.id).cloned(); - let (autoderefs, unsize) = match adj { - Some(AdjustDerefRef(adr)) => match adr.autoref { - None => { - assert!(adr.unsize.is_none()); - (adr.autoderefs, None) + let (autoderefs, unsize, adjusted_base_ty) = match adj { + Some(Adjustment { + kind: Adjust::DerefRef { autoderefs, autoref, unsize }, + target + }) => { + match autoref { + None => { + assert!(!unsize); + } + Some(AutoBorrow::Ref(..)) => {} + Some(_) => { + span_bug!(base_expr.span, + "unexpected adjustment autoref {:?}", + adj); + } } - Some(AutoPtr(..)) => { - (adr.autoderefs, adr.unsize.map(|target| { - target.builtin_deref(false, NoPreference) - .expect("fixup: AutoPtr is not &T").ty - })) - } - Some(_) => { - span_bug!( - base_expr.span, - "unexpected adjustment autoref {:?}", - adr); - } - }, - None => (0, None), + + (autoderefs, unsize, if unsize { + target.builtin_deref(false, NoPreference) + .expect("fixup: AutoBorrow::Ref is not &T") + .ty + } else { + let ty = self.node_ty(base_expr.id); + let mut ty = self.shallow_resolve(ty); + let mut method_type = |method_call: ty::MethodCall| { + self.tables.borrow().method_map.get(&method_call).map(|m| { + self.resolve_type_vars_if_possible(&m.ty) + }) + }; + + if !ty.references_error() { + for i in 0..autoderefs { + ty = ty.adjust_for_autoderef(self.tcx, + base_expr.id, + base_expr.span, + i as u32, + &mut method_type); + } + } + + ty + }) + } + None => (0, false, self.node_ty(base_expr.id)), Some(_) => { - span_bug!( - base_expr.span, - "unexpected adjustment type"); + span_bug!(base_expr.span, "unexpected adjustment type"); } }; - let (adjusted_base_ty, unsize) = if let Some(target) = unsize { - (target, true) - } else { - (self.adjust_expr_ty(base_expr, - Some(&AdjustDerefRef(AutoDerefRef { - autoderefs: autoderefs, - autoref: None, - unsize: None - }))), false) - }; let index_expr_ty = self.node_ty(index_expr.id); - let result = self.try_index_step( - ty::MethodCall::expr(expr.id), - expr, - &base_expr, - adjusted_base_ty, - autoderefs, - unsize, - PreferMutLvalue, - index_expr_ty); + let result = self.try_index_step(ty::MethodCall::expr(expr.id), + expr, + &base_expr, + adjusted_base_ty, + autoderefs, + unsize, + PreferMutLvalue, + index_expr_ty); if let Some((input_ty, return_ty)) = result { self.demand_suptype(index_expr.span, input_ty, index_expr_ty); @@ -557,9 +570,9 @@ impl<'a, 'gcx, 'tcx> ConfirmContext<'a, 'gcx, 'tcx> { let method_call = ty::MethodCall::expr(expr.id); if self.tables.borrow().method_map.contains_key(&method_call) { let method = self.try_overloaded_deref(expr.span, - Some(&base_expr), - self.node_ty(base_expr.id), - PreferMutLvalue); + Some(&base_expr), + self.node_ty(base_expr.id), + PreferMutLvalue); let method = method.expect("re-trying deref failed"); self.tables.borrow_mut().method_map.insert(method_call, method); } @@ -585,28 +598,27 @@ impl<'a, 'gcx, 'tcx> ConfirmContext<'a, 'gcx, 'tcx> { fn upcast(&mut self, source_trait_ref: ty::PolyTraitRef<'tcx>, target_trait_def_id: DefId) - -> ty::PolyTraitRef<'tcx> - { - let upcast_trait_refs = self.tcx.upcast_choices(source_trait_ref.clone(), - target_trait_def_id); + -> ty::PolyTraitRef<'tcx> { + let upcast_trait_refs = self.tcx + .upcast_choices(source_trait_ref.clone(), target_trait_def_id); // must be exactly one trait ref or we'd get an ambig error etc if upcast_trait_refs.len() != 1 { - span_bug!( - self.span, - "cannot uniquely upcast `{:?}` to `{:?}`: `{:?}`", - source_trait_ref, - target_trait_def_id, - upcast_trait_refs); + span_bug!(self.span, + "cannot uniquely upcast `{:?}` to `{:?}`: `{:?}`", + source_trait_ref, + target_trait_def_id, + upcast_trait_refs); } upcast_trait_refs.into_iter().next().unwrap() } fn replace_late_bound_regions_with_fresh_var(&self, value: &ty::Binder) -> T - where T : TypeFoldable<'tcx> + where T: TypeFoldable<'tcx> { - self.fcx.replace_late_bound_regions_with_fresh_var( - self.span, infer::FnCall, value).0 + self.fcx + .replace_late_bound_regions_with_fresh_var(self.span, infer::FnCall, value) + .0 } } diff --git a/src/librustc_typeck/check/method/mod.rs b/src/librustc_typeck/check/method/mod.rs index 73caf79c9f..2df562f9ad 100644 --- a/src/librustc_typeck/check/method/mod.rs +++ b/src/librustc_typeck/check/method/mod.rs @@ -16,7 +16,7 @@ use hir::def_id::DefId; use rustc::ty::subst::Substs; use rustc::traits; use rustc::ty::{self, ToPredicate, ToPolyTraitRef, TraitRef, TypeFoldable}; -use rustc::ty::adjustment::{AdjustDerefRef, AutoDerefRef, AutoPtr}; +use rustc::ty::adjustment::{Adjustment, Adjust, AutoBorrow}; use rustc::infer; use syntax::ast; @@ -41,7 +41,8 @@ pub enum MethodError<'tcx> { Ambiguity(Vec), // Using a `Fn`/`FnMut`/etc method on a raw closure type before we have inferred its kind. - ClosureAmbiguity(/* DefId of fn trait */ DefId), + ClosureAmbiguity(// DefId of fn trait + DefId), // Found an applicable method, but it is not visible. PrivateMatch(Def), @@ -53,19 +54,20 @@ pub struct NoMatchData<'tcx> { pub static_candidates: Vec, pub unsatisfied_predicates: Vec>, pub out_of_scope_traits: Vec, - pub mode: probe::Mode + pub mode: probe::Mode, } impl<'tcx> NoMatchData<'tcx> { pub fn new(static_candidates: Vec, unsatisfied_predicates: Vec>, out_of_scope_traits: Vec, - mode: probe::Mode) -> Self { + mode: probe::Mode) + -> Self { NoMatchData { static_candidates: static_candidates, unsatisfied_predicates: unsatisfied_predicates, out_of_scope_traits: out_of_scope_traits, - mode: mode + mode: mode, } } } @@ -75,7 +77,8 @@ impl<'tcx> NoMatchData<'tcx> { #[derive(Copy, Clone, Debug, Eq, Ord, PartialEq, PartialOrd)] pub enum CandidateSource { ImplSource(DefId), - TraitSource(/* trait id */ DefId), + TraitSource(// trait id + DefId), } impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { @@ -86,8 +89,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { self_ty: ty::Ty<'tcx>, call_expr_id: ast::NodeId, allow_private: bool) - -> bool - { + -> bool { let mode = probe::Mode::MethodCall; match self.probe_method(span, mode, method_name, self_ty, call_expr_id) { Ok(..) => true, @@ -119,8 +121,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { supplied_method_types: Vec>, call_expr: &'gcx hir::Expr, self_expr: &'gcx hir::Expr) - -> Result, MethodError<'tcx>> - { + -> Result, MethodError<'tcx>> { debug!("lookup(method_name={}, self_ty={:?}, call_expr={:?}, self_expr={:?})", method_name, self_ty, @@ -135,7 +136,12 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { self.tcx.used_trait_imports.borrow_mut().insert(import_id); } - Ok(self.confirm_method(span, self_expr, call_expr, self_ty, pick, supplied_method_types)) + Ok(self.confirm_method(span, + self_expr, + call_expr, + self_ty, + pick, + supplied_method_types)) } pub fn lookup_method_in_trait(&self, @@ -145,10 +151,15 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { trait_def_id: DefId, self_ty: ty::Ty<'tcx>, opt_input_types: Option>>) - -> Option> - { - self.lookup_method_in_trait_adjusted(span, self_expr, m_name, trait_def_id, - 0, false, self_ty, opt_input_types) + -> Option> { + self.lookup_method_in_trait_adjusted(span, + self_expr, + m_name, + trait_def_id, + 0, + false, + self_ty, + opt_input_types) } /// `lookup_in_trait_adjusted` is used for overloaded operators. @@ -171,8 +182,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { unsize: bool, self_ty: ty::Ty<'tcx>, opt_input_types: Option>>) - -> Option> - { + -> Option> { debug!("lookup_in_trait_adjusted(self_ty={:?}, self_expr={:?}, \ m_name={}, trait_def_id={:?})", self_ty, @@ -188,9 +198,10 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { assert!(trait_def.generics.regions.is_empty()); // Construct a trait-reference `self_ty : Trait` - let substs = Substs::for_item(self.tcx, trait_def_id, |def, _| { - self.region_var_for_def(span, def) - }, |def, substs| { + let substs = Substs::for_item(self.tcx, + trait_def_id, + |def, _| self.region_var_for_def(span, def), + |def, substs| { if def.index == 0 { self_ty } else if let Some(ref input_types) = opt_input_types { @@ -204,9 +215,8 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { // Construct an obligation let poly_trait_ref = trait_ref.to_poly_trait_ref(); - let obligation = traits::Obligation::misc(span, - self.body_id, - poly_trait_ref.to_predicate()); + let obligation = + traits::Obligation::misc(span, self.body_id, poly_trait_ref.to_predicate()); // Now we want to know if this can be matched let mut selcx = traits::SelectionContext::new(self); @@ -224,7 +234,8 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { assert_eq!(method_ty.generics.regions.len(), 0); debug!("lookup_in_trait_adjusted: method_item={:?} method_ty={:?}", - method_item, method_ty); + method_item, + method_ty); // Instantiate late-bound regions and substitute the trait // parameters into the method type to get the actual method type. @@ -232,18 +243,19 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { // NB: Instantiate late-bound regions first so that // `instantiate_type_scheme` can normalize associated types that // may reference those regions. - let fn_sig = self.replace_late_bound_regions_with_fresh_var(span, - infer::FnCall, - &method_ty.fty.sig).0; + let fn_sig = + self.replace_late_bound_regions_with_fresh_var(span, infer::FnCall, &method_ty.fty.sig) + .0; let fn_sig = self.instantiate_type_scheme(span, trait_ref.substs, &fn_sig); let transformed_self_ty = fn_sig.inputs[0]; let def_id = method_item.def_id(); - let fty = tcx.mk_fn_def(def_id, trait_ref.substs, + let fty = tcx.mk_fn_def(def_id, + trait_ref.substs, tcx.mk_bare_fn(ty::BareFnTy { - sig: ty::Binder(fn_sig), - unsafety: method_ty.fty.unsafety, - abi: method_ty.fty.abi.clone(), - })); + sig: ty::Binder(fn_sig), + unsafety: method_ty.fty.unsafety, + abi: method_ty.fty.abi.clone(), + })); debug!("lookup_in_trait_adjusted: matched method fty={:?} obligation={:?}", fty, @@ -259,9 +271,8 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { // any late-bound regions appearing in its bounds. let method_bounds = self.instantiate_bounds(span, trait_ref.substs, &method_ty.predicates); assert!(!method_bounds.has_escaping_regions()); - self.add_obligations_for_parameters( - traits::ObligationCause::misc(span, self.body_id), - &method_bounds); + self.add_obligations_for_parameters(traits::ObligationCause::misc(span, self.body_id), + &method_bounds); // Also register an obligation for the method type being well-formed. self.register_wf_obligation(fty, span, traits::MiscObligation); @@ -273,19 +284,21 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { // Insert any adjustments needed (always an autoref of some mutability). match self_expr { - None => { } + None => {} Some(self_expr) => { debug!("lookup_in_trait_adjusted: inserting adjustment if needed \ (self-id={}, autoderefs={}, unsize={}, explicit_self={:?})", - self_expr.id, autoderefs, unsize, + self_expr.id, + autoderefs, + unsize, method_ty.explicit_self); - match method_ty.explicit_self { + let autoref = match method_ty.explicit_self { ty::ExplicitSelfCategory::ByValue => { // Trait method is fn(self), no transformation needed. assert!(!unsize); - self.write_autoderef_adjustment(self_expr.id, autoderefs); + None } ty::ExplicitSelfCategory::ByReference(..) => { @@ -293,41 +306,39 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { // autoref. Pull the region etc out of the type of first argument. match transformed_self_ty.sty { ty::TyRef(region, ty::TypeAndMut { mutbl, ty: _ }) => { - self.write_adjustment(self_expr.id, - AdjustDerefRef(AutoDerefRef { - autoderefs: autoderefs, - autoref: Some(AutoPtr(region, mutbl)), - unsize: if unsize { - Some(transformed_self_ty) - } else { - None - } - })); + Some(AutoBorrow::Ref(region, mutbl)) } _ => { - span_bug!( - span, - "trait method is &self but first arg is: {}", - transformed_self_ty); + span_bug!(span, + "trait method is &self but first arg is: {}", + transformed_self_ty); } } } _ => { - span_bug!( - span, - "unexpected explicit self type in operator method: {:?}", - method_ty.explicit_self); + span_bug!(span, + "unexpected explicit self type in operator method: {:?}", + method_ty.explicit_self); } - } + }; + + self.write_adjustment(self_expr.id, Adjustment { + kind: Adjust::DerefRef { + autoderefs: autoderefs, + autoref: autoref, + unsize: unsize + }, + target: transformed_self_ty + }); } } let callee = ty::MethodCallee { def_id: def_id, ty: fty, - substs: trait_ref.substs + substs: trait_ref.substs, }; debug!("callee = {:?}", callee); @@ -340,8 +351,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { method_name: ast::Name, self_ty: ty::Ty<'tcx>, expr_id: ast::NodeId) - -> Result> - { + -> Result> { let mode = probe::Mode::Path; let pick = self.probe_method(span, mode, method_name, self_ty, expr_id)?; @@ -364,9 +374,9 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { pub fn impl_or_trait_item(&self, def_id: DefId, item_name: ast::Name) - -> Option> - { - self.tcx.impl_or_trait_items(def_id) + -> Option> { + self.tcx + .impl_or_trait_items(def_id) .iter() .map(|&did| self.tcx.impl_or_trait_item(did)) .find(|m| m.name() == item_name) diff --git a/src/librustc_typeck/check/method/probe.rs b/src/librustc_typeck/check/method/probe.rs index 9fba9bcb75..43837de2f3 100644 --- a/src/librustc_typeck/check/method/probe.rs +++ b/src/librustc_typeck/check/method/probe.rs @@ -13,7 +13,7 @@ use super::NoMatchData; use super::{CandidateSource, ImplSource, TraitSource}; use super::suggest; -use check::{FnCtxt}; +use check::FnCtxt; use hir::def_id::DefId; use hir::def::Def; use rustc::ty::subst::{Subst, Substs}; @@ -31,7 +31,7 @@ use std::rc::Rc; use self::CandidateKind::*; pub use self::PickKind::*; -struct ProbeContext<'a, 'gcx: 'a+'tcx, 'tcx: 'a> { +struct ProbeContext<'a, 'gcx: 'a + 'tcx, 'tcx: 'a> { fcx: &'a FnCtxt<'a, 'gcx, 'tcx>, span: Span, mode: Mode, @@ -52,7 +52,7 @@ struct ProbeContext<'a, 'gcx: 'a+'tcx, 'tcx: 'a> { /// Collects near misses when trait bounds for type parameters are unsatisfied and is only used /// for error reporting - unsatisfied_predicates: Vec> + unsatisfied_predicates: Vec>, } impl<'a, 'gcx, 'tcx> Deref for ProbeContext<'a, 'gcx, 'tcx> { @@ -66,7 +66,7 @@ impl<'a, 'gcx, 'tcx> Deref for ProbeContext<'a, 'gcx, 'tcx> { struct CandidateStep<'tcx> { self_ty: Ty<'tcx>, autoderefs: usize, - unsize: bool + unsize: bool, } #[derive(Debug)] @@ -80,12 +80,17 @@ struct Candidate<'tcx> { #[derive(Debug)] enum CandidateKind<'tcx> { InherentImplCandidate(&'tcx Substs<'tcx>, - /* Normalize obligations */ Vec>), - ExtensionImplCandidate(/* Impl */ DefId, &'tcx Substs<'tcx>, - /* Normalize obligations */ Vec>), + // Normalize obligations + Vec>), + ExtensionImplCandidate(// Impl + DefId, + &'tcx Substs<'tcx>, + // Normalize obligations + Vec>), ObjectCandidate, TraitCandidate, - WhereClauseCandidate(/* Trait */ ty::PolyTraitRef<'tcx>), + WhereClauseCandidate(// Trait + ty::PolyTraitRef<'tcx>), } #[derive(Debug)] @@ -115,10 +120,12 @@ pub struct Pick<'tcx> { #[derive(Clone,Debug)] pub enum PickKind<'tcx> { InherentImplPick, - ExtensionImplPick(/* Impl */ DefId), + ExtensionImplPick(// Impl + DefId), ObjectPick, TraitPick, - WhereClausePick(/* Trait */ ty::PolyTraitRef<'tcx>), + WhereClausePick(// Trait + ty::PolyTraitRef<'tcx>), } pub type PickResult<'tcx> = Result, MethodError<'tcx>>; @@ -132,7 +139,7 @@ pub enum Mode { // An expression of the form `Type::item` or `::item`. // No autoderefs are performed, lookup is done based on the type each // implementation is for, and static methods are included. - Path + Path, } impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { @@ -142,8 +149,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { item_name: ast::Name, self_ty: Ty<'tcx>, scope_expr_id: ast::NodeId) - -> PickResult<'tcx> - { + -> PickResult<'tcx> { debug!("probe(self_ty={:?}, item_name={}, scope_expr_id={})", self_ty, item_name, @@ -159,31 +165,38 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { let steps = if mode == Mode::MethodCall { match self.create_steps(span, self_ty) { Some(steps) => steps, - None =>return Err(MethodError::NoMatch(NoMatchData::new(Vec::new(), Vec::new(), - Vec::new(), mode))), + None => { + return Err(MethodError::NoMatch(NoMatchData::new(Vec::new(), + Vec::new(), + Vec::new(), + mode))) + } } } else { vec![CandidateStep { - self_ty: self_ty, - autoderefs: 0, - unsize: false - }] + self_ty: self_ty, + autoderefs: 0, + unsize: false, + }] }; // Create a list of simplified self types, if we can. let mut simplified_steps = Vec::new(); for step in &steps { match ty::fast_reject::simplify_type(self.tcx, step.self_ty, true) { - None => { break; } - Some(simplified_type) => { simplified_steps.push(simplified_type); } + None => { + break; + } + Some(simplified_type) => { + simplified_steps.push(simplified_type); + } } } - let opt_simplified_steps = - if simplified_steps.len() < steps.len() { - None // failed to convert at least one of the steps - } else { - Some(simplified_steps) - }; + let opt_simplified_steps = if simplified_steps.len() < steps.len() { + None // failed to convert at least one of the steps + } else { + Some(simplified_steps) + }; debug!("ProbeContext: steps for self_ty={:?} are {:?}", self_ty, @@ -192,31 +205,27 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { // this creates one big transaction so that all type variables etc // that we create during the probe process are removed later self.probe(|_| { - let mut probe_cx = ProbeContext::new(self, - span, - mode, - item_name, - steps, - opt_simplified_steps); + let mut probe_cx = + ProbeContext::new(self, span, mode, item_name, steps, opt_simplified_steps); probe_cx.assemble_inherent_candidates(); probe_cx.assemble_extension_candidates_for_traits_in_scope(scope_expr_id)?; probe_cx.pick() }) } - fn create_steps(&self, - span: Span, - self_ty: Ty<'tcx>) - -> Option>> - { + fn create_steps(&self, span: Span, self_ty: Ty<'tcx>) -> Option>> { // FIXME: we don't need to create the entire steps in one pass let mut autoderef = self.autoderef(span, self_ty); - let mut steps: Vec<_> = autoderef.by_ref().map(|(ty, d)| CandidateStep { - self_ty: ty, - autoderefs: d, - unsize: false - }).collect(); + let mut steps: Vec<_> = autoderef.by_ref() + .map(|(ty, d)| { + CandidateStep { + self_ty: ty, + autoderefs: d, + unsize: false, + } + }) + .collect(); let final_ty = autoderef.unambiguous_final_ty(); match final_ty.sty { @@ -226,7 +235,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { steps.push(CandidateStep { self_ty: self.tcx.mk_slice(elem_ty), autoderefs: dereferences, - unsize: true + unsize: true, }); } ty::TyError => return None, @@ -246,8 +255,7 @@ impl<'a, 'gcx, 'tcx> ProbeContext<'a, 'gcx, 'tcx> { item_name: ast::Name, steps: Vec>, opt_simplified_steps: Option>) - -> ProbeContext<'a, 'gcx, 'tcx> - { + -> ProbeContext<'a, 'gcx, 'tcx> { ProbeContext { fcx: fcx, span: span, @@ -284,8 +292,7 @@ impl<'a, 'gcx, 'tcx> ProbeContext<'a, 'gcx, 'tcx> { } fn assemble_probe(&mut self, self_ty: Ty<'tcx>) { - debug!("assemble_probe: self_ty={:?}", - self_ty); + debug!("assemble_probe: self_ty={:?}", self_ty); match self_ty.sty { ty::TyTrait(box ref data) => { @@ -371,8 +378,7 @@ impl<'a, 'gcx, 'tcx> ProbeContext<'a, 'gcx, 'tcx> { let lang_def_id = self.tcx.lang_items.f64_impl(); self.assemble_inherent_impl_for_primitive(lang_def_id); } - _ => { - } + _ => {} } } @@ -405,7 +411,9 @@ impl<'a, 'gcx, 'tcx> ProbeContext<'a, 'gcx, 'tcx> { let item = match self.impl_or_trait_item(impl_def_id) { Some(m) => m, - None => { return; } // No method with correct name on this impl + None => { + return; + } // No method with correct name on this impl }; if !self.has_applicable_self(&item) { @@ -415,7 +423,7 @@ impl<'a, 'gcx, 'tcx> ProbeContext<'a, 'gcx, 'tcx> { if !item.vis().is_accessible_from(self.body_id, &self.tcx.map) { self.private_candidate = Some(item.def()); - return + return; } let (impl_ty, impl_substs) = self.impl_ty_and_substs(impl_def_id); @@ -458,9 +466,8 @@ impl<'a, 'gcx, 'tcx> ProbeContext<'a, 'gcx, 'tcx> { self.elaborate_bounds(&[trait_ref], |this, new_trait_ref, item| { let new_trait_ref = this.erase_late_bound_regions(&new_trait_ref); - let xform_self_ty = this.xform_self_ty(&item, - new_trait_ref.self_ty(), - new_trait_ref.substs); + let xform_self_ty = + this.xform_self_ty(&item, new_trait_ref.self_ty(), new_trait_ref.substs); this.inherent_candidates.push(Candidate { xform_self_ty: xform_self_ty, @@ -476,8 +483,8 @@ impl<'a, 'gcx, 'tcx> ProbeContext<'a, 'gcx, 'tcx> { param_ty: ty::ParamTy) { // FIXME -- Do we want to commit to this behavior for param bounds? - let bounds: Vec<_> = - self.parameter_environment.caller_bounds + let bounds: Vec<_> = self.parameter_environment + .caller_bounds .iter() .filter_map(|predicate| { match *predicate { @@ -486,7 +493,7 @@ impl<'a, 'gcx, 'tcx> ProbeContext<'a, 'gcx, 'tcx> { ty::TyParam(ref p) if *p == param_ty => { Some(trait_predicate.to_poly_trait_ref()) } - _ => None + _ => None, } } ty::Predicate::Equate(..) | @@ -495,21 +502,15 @@ impl<'a, 'gcx, 'tcx> ProbeContext<'a, 'gcx, 'tcx> { ty::Predicate::WellFormed(..) | ty::Predicate::ObjectSafe(..) | ty::Predicate::ClosureKind(..) | - ty::Predicate::TypeOutlives(..) => { - None - } + ty::Predicate::TypeOutlives(..) => None, } }) .collect(); self.elaborate_bounds(&bounds, |this, poly_trait_ref, item| { - let trait_ref = - this.erase_late_bound_regions(&poly_trait_ref); + let trait_ref = this.erase_late_bound_regions(&poly_trait_ref); - let xform_self_ty = - this.xform_self_ty(&item, - trait_ref.self_ty(), - trait_ref.substs); + let xform_self_ty = this.xform_self_ty(&item, trait_ref.self_ty(), trait_ref.substs); if let Some(ref m) = item.as_opt_method() { debug!("found match: trait_ref={:?} substs={:?} m={:?}", @@ -540,16 +541,10 @@ impl<'a, 'gcx, 'tcx> ProbeContext<'a, 'gcx, 'tcx> { // Do a search through a list of bounds, using a callback to actually // create the candidates. - fn elaborate_bounds( - &mut self, - bounds: &[ty::PolyTraitRef<'tcx>], - mut mk_cand: F, - ) where - F: for<'b> FnMut( - &mut ProbeContext<'b, 'gcx, 'tcx>, - ty::PolyTraitRef<'tcx>, - ty::ImplOrTraitItem<'tcx>, - ), + fn elaborate_bounds(&mut self, bounds: &[ty::PolyTraitRef<'tcx>], mut mk_cand: F) + where F: for<'b> FnMut(&mut ProbeContext<'b, 'gcx, 'tcx>, + ty::PolyTraitRef<'tcx>, + ty::ImplOrTraitItem<'tcx>) { debug!("elaborate_bounds(bounds={:?})", bounds); @@ -557,7 +552,9 @@ impl<'a, 'gcx, 'tcx> ProbeContext<'a, 'gcx, 'tcx> { for bound_trait_ref in traits::transitive_bounds(tcx, bounds) { let item = match self.impl_or_trait_item(bound_trait_ref.def_id()) { Some(v) => v, - None => { continue; } + None => { + continue; + } }; if !self.has_applicable_self(&item) { @@ -570,8 +567,7 @@ impl<'a, 'gcx, 'tcx> ProbeContext<'a, 'gcx, 'tcx> { fn assemble_extension_candidates_for_traits_in_scope(&mut self, expr_id: ast::NodeId) - -> Result<(), MethodError<'tcx>> - { + -> Result<(), MethodError<'tcx>> { let mut duplicates = FnvHashSet(); let opt_applicable_traits = self.tcx.trait_map.get(&expr_id); if let Some(applicable_traits) = opt_applicable_traits { @@ -600,20 +596,19 @@ impl<'a, 'gcx, 'tcx> ProbeContext<'a, 'gcx, 'tcx> { fn assemble_extension_candidates_for_trait(&mut self, trait_def_id: DefId) - -> Result<(), MethodError<'tcx>> - { + -> Result<(), MethodError<'tcx>> { debug!("assemble_extension_candidates_for_trait(trait_def_id={:?})", trait_def_id); // Check whether `trait_def_id` defines a method with suitable name: - let trait_items = - self.tcx.trait_items(trait_def_id); - let maybe_item = - trait_items.iter() - .find(|item| item.name() == self.item_name); + let trait_items = self.tcx.trait_items(trait_def_id); + let maybe_item = trait_items.iter() + .find(|item| item.name() == self.item_name); let item = match maybe_item { Some(i) => i, - None => { return Ok(()); } + None => { + return Ok(()); + } }; // Check whether `trait_def_id` defines a method with suitable name: @@ -636,8 +631,7 @@ impl<'a, 'gcx, 'tcx> ProbeContext<'a, 'gcx, 'tcx> { fn assemble_extension_candidates_for_trait_impls(&mut self, trait_def_id: DefId, - item: ty::ImplOrTraitItem<'tcx>) - { + item: ty::ImplOrTraitItem<'tcx>) { let trait_def = self.tcx.lookup_trait_def(trait_def_id); // FIXME(arielb1): can we use for_each_relevant_impl here? @@ -655,8 +649,7 @@ impl<'a, 'gcx, 'tcx> ProbeContext<'a, 'gcx, 'tcx> { debug!("impl_substs={:?}", impl_substs); - let impl_trait_ref = - self.tcx.impl_trait_ref(impl_def_id) + let impl_trait_ref = self.tcx.impl_trait_ref(impl_def_id) .unwrap() // we know this is a trait impl .subst(self.tcx, impl_substs); @@ -664,9 +657,7 @@ impl<'a, 'gcx, 'tcx> ProbeContext<'a, 'gcx, 'tcx> { // Determine the receiver type that the method itself expects. let xform_self_ty = - self.xform_self_ty(&item, - impl_trait_ref.self_ty(), - impl_trait_ref.substs); + self.xform_self_ty(&item, impl_trait_ref.self_ty(), impl_trait_ref.substs); // Normalize the receiver. We can't use normalize_associated_types_in // as it will pollute the fcx's fulfillment context after this probe @@ -690,14 +681,18 @@ impl<'a, 'gcx, 'tcx> ProbeContext<'a, 'gcx, 'tcx> { fn impl_can_possibly_match(&self, impl_def_id: DefId) -> bool { let simplified_steps = match self.opt_simplified_steps { Some(ref simplified_steps) => simplified_steps, - None => { return true; } + None => { + return true; + } }; let impl_type = self.tcx.lookup_item_type(impl_def_id); let impl_simplified_type = match ty::fast_reject::simplify_type(self.tcx, impl_type.ty, false) { Some(simplified_type) => simplified_type, - None => { return true; } + None => { + return true; + } }; simplified_steps.contains(&impl_simplified_type) @@ -706,8 +701,7 @@ impl<'a, 'gcx, 'tcx> ProbeContext<'a, 'gcx, 'tcx> { fn assemble_closure_candidates(&mut self, trait_def_id: DefId, item: ty::ImplOrTraitItem<'tcx>) - -> Result<(), MethodError<'tcx>> - { + -> Result<(), MethodError<'tcx>> { // Check if this is one of the Fn,FnMut,FnOnce traits. let tcx = self.tcx; let kind = if Some(trait_def_id) == tcx.lang_items.fn_trait() { @@ -746,9 +740,10 @@ impl<'a, 'gcx, 'tcx> ProbeContext<'a, 'gcx, 'tcx> { // for the purposes of our method lookup, we only take // receiver type into account, so we can just substitute // fresh types here to use during substitution and subtyping. - let substs = Substs::for_item(self.tcx, trait_def_id, |def, _| { - self.region_var_for_def(self.span, def) - }, |def, substs| { + let substs = Substs::for_item(self.tcx, + trait_def_id, + |def, _| self.region_var_for_def(self.span, def), + |def, substs| { if def.index == 0 { step.self_ty } else { @@ -756,9 +751,7 @@ impl<'a, 'gcx, 'tcx> ProbeContext<'a, 'gcx, 'tcx> { } }); - let xform_self_ty = self.xform_self_ty(&item, - step.self_ty, - substs); + let xform_self_ty = self.xform_self_ty(&item, step.self_ty, substs); self.inherent_candidates.push(Candidate { xform_self_ty: xform_self_ty, item: item.clone(), @@ -772,8 +765,7 @@ impl<'a, 'gcx, 'tcx> ProbeContext<'a, 'gcx, 'tcx> { fn assemble_projection_candidates(&mut self, trait_def_id: DefId, - item: ty::ImplOrTraitItem<'tcx>) - { + item: ty::ImplOrTraitItem<'tcx>) { debug!("assemble_projection_candidates(\ trait_def_id={:?}, \ item={:?})", @@ -781,39 +773,35 @@ impl<'a, 'gcx, 'tcx> ProbeContext<'a, 'gcx, 'tcx> { item); for step in self.steps.iter() { - debug!("assemble_projection_candidates: step={:?}", - step); + debug!("assemble_projection_candidates: step={:?}", step); let (def_id, substs) = match step.self_ty.sty { - ty::TyProjection(ref data) => { - (data.trait_ref.def_id, data.trait_ref.substs) - } + ty::TyProjection(ref data) => (data.trait_ref.def_id, data.trait_ref.substs), ty::TyAnon(def_id, substs) => (def_id, substs), _ => continue, }; debug!("assemble_projection_candidates: def_id={:?} substs={:?}", - def_id, substs); + def_id, + substs); let trait_predicates = self.tcx.lookup_predicates(def_id); let bounds = trait_predicates.instantiate(self.tcx, substs); let predicates = bounds.predicates; debug!("assemble_projection_candidates: predicates={:?}", predicates); - for poly_bound in - traits::elaborate_predicates(self.tcx, predicates) + for poly_bound in traits::elaborate_predicates(self.tcx, predicates) .filter_map(|p| p.to_opt_poly_trait_ref()) - .filter(|b| b.def_id() == trait_def_id) - { + .filter(|b| b.def_id() == trait_def_id) { let bound = self.erase_late_bound_regions(&poly_bound); debug!("assemble_projection_candidates: def_id={:?} substs={:?} bound={:?}", - def_id, substs, bound); + def_id, + substs, + bound); if self.can_equate(&step.self_ty, &bound.self_ty()).is_ok() { - let xform_self_ty = self.xform_self_ty(&item, - bound.self_ty(), - bound.substs); + let xform_self_ty = self.xform_self_ty(&item, bound.self_ty(), bound.substs); debug!("assemble_projection_candidates: bound={:?} xform_self_ty={:?}", bound, @@ -832,20 +820,16 @@ impl<'a, 'gcx, 'tcx> ProbeContext<'a, 'gcx, 'tcx> { fn assemble_where_clause_candidates(&mut self, trait_def_id: DefId, - item: ty::ImplOrTraitItem<'tcx>) - { + item: ty::ImplOrTraitItem<'tcx>) { debug!("assemble_where_clause_candidates(trait_def_id={:?})", trait_def_id); let caller_predicates = self.parameter_environment.caller_bounds.clone(); for poly_bound in traits::elaborate_predicates(self.tcx, caller_predicates) - .filter_map(|p| p.to_opt_poly_trait_ref()) - .filter(|b| b.def_id() == trait_def_id) - { + .filter_map(|p| p.to_opt_poly_trait_ref()) + .filter(|b| b.def_id() == trait_def_id) { let bound = self.erase_late_bound_regions(&poly_bound); - let xform_self_ty = self.xform_self_ty(&item, - bound.self_ty(), - bound.substs); + let xform_self_ty = self.xform_self_ty(&item, bound.self_ty(), bound.substs); debug!("assemble_where_clause_candidates: bound={:?} xform_self_ty={:?}", bound, @@ -882,19 +866,24 @@ impl<'a, 'gcx, 'tcx> ProbeContext<'a, 'gcx, 'tcx> { let out_of_scope_traits = match self.pick_core() { Some(Ok(p)) => vec![p.item.container().id()], - Some(Err(MethodError::Ambiguity(v))) => v.into_iter().map(|source| { - match source { - TraitSource(id) => id, - ImplSource(impl_id) => { - match tcx.trait_id_of_impl(impl_id) { - Some(id) => id, - None => - span_bug!(span, - "found inherent method when looking at traits") + Some(Err(MethodError::Ambiguity(v))) => { + v.into_iter() + .map(|source| { + match source { + TraitSource(id) => id, + ImplSource(impl_id) => { + match tcx.trait_id_of_impl(impl_id) { + Some(id) => id, + None => { + span_bug!(span, + "found inherent method when looking at traits") + } + } + } } - } - } - }).collect(), + }) + .collect() + } Some(Err(MethodError::NoMatch(NoMatchData { out_of_scope_traits: others, .. }))) => { assert!(others.is_empty()); vec![] @@ -910,8 +899,10 @@ impl<'a, 'gcx, 'tcx> ProbeContext<'a, 'gcx, 'tcx> { return Err(MethodError::PrivateMatch(def)); } - Err(MethodError::NoMatch(NoMatchData::new(static_candidates, unsatisfied_predicates, - out_of_scope_traits, self.mode))) + Err(MethodError::NoMatch(NoMatchData::new(static_candidates, + unsatisfied_predicates, + out_of_scope_traits, + self.mode))) } fn pick_core(&mut self) -> Option> { @@ -935,41 +926,35 @@ impl<'a, 'gcx, 'tcx> ProbeContext<'a, 'gcx, 'tcx> { self.pick_autorefd_method(step) } - fn pick_by_value_method(&mut self, - step: &CandidateStep<'tcx>) - -> Option> - { - /*! - * For each type `T` in the step list, this attempts to find a - * method where the (transformed) self type is exactly `T`. We - * do however do one transformation on the adjustment: if we - * are passing a region pointer in, we will potentially - * *reborrow* it to a shorter lifetime. This allows us to - * transparently pass `&mut` pointers, in particular, without - * consuming them for their entire lifetime. - */ + fn pick_by_value_method(&mut self, step: &CandidateStep<'tcx>) -> Option> { + //! For each type `T` in the step list, this attempts to find a + //! method where the (transformed) self type is exactly `T`. We + //! do however do one transformation on the adjustment: if we + //! are passing a region pointer in, we will potentially + //! *reborrow* it to a shorter lifetime. This allows us to + //! transparently pass `&mut` pointers, in particular, without + //! consuming them for their entire lifetime. if step.unsize { return None; } - self.pick_method(step.self_ty).map(|r| r.map(|mut pick| { - pick.autoderefs = step.autoderefs; + self.pick_method(step.self_ty).map(|r| { + r.map(|mut pick| { + pick.autoderefs = step.autoderefs; - // Insert a `&*` or `&mut *` if this is a reference type: - if let ty::TyRef(_, mt) = step.self_ty.sty { - pick.autoderefs += 1; - pick.autoref = Some(mt.mutbl); - } + // Insert a `&*` or `&mut *` if this is a reference type: + if let ty::TyRef(_, mt) = step.self_ty.sty { + pick.autoderefs += 1; + pick.autoref = Some(mt.mutbl); + } - pick - })) + pick + }) + }) } - fn pick_autorefd_method(&mut self, - step: &CandidateStep<'tcx>) - -> Option> - { + fn pick_autorefd_method(&mut self, step: &CandidateStep<'tcx>) -> Option> { let tcx = self.tcx; // In general, during probing we erase regions. See @@ -977,22 +962,28 @@ impl<'a, 'gcx, 'tcx> ProbeContext<'a, 'gcx, 'tcx> { let region = tcx.mk_region(ty::ReErased); // Search through mutabilities in order to find one where pick works: - [hir::MutImmutable, hir::MutMutable].iter().filter_map(|&m| { - let autoref_ty = tcx.mk_ref(region, ty::TypeAndMut { - 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) + [hir::MutImmutable, hir::MutMutable] + .iter() + .filter_map(|&m| { + let autoref_ty = tcx.mk_ref(region, + ty::TypeAndMut { + 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> { @@ -1008,7 +999,8 @@ impl<'a, 'gcx, 'tcx> ProbeContext<'a, 'gcx, 'tcx> { } debug!("searching extension candidates"); - let res = self.consider_candidates(self_ty, &self.extension_candidates, + let res = self.consider_candidates(self_ty, + &self.extension_candidates, &mut possibly_unsatisfied_predicates); if let None = res { self.unsatisfied_predicates.extend(possibly_unsatisfied_predicates); @@ -1021,18 +1013,18 @@ impl<'a, 'gcx, 'tcx> ProbeContext<'a, 'gcx, 'tcx> { probes: &[Candidate<'tcx>], possibly_unsatisfied_predicates: &mut Vec>) -> Option> { - let mut applicable_candidates: Vec<_> = - probes.iter() - .filter(|&probe| self.consider_probe(self_ty, - probe,possibly_unsatisfied_predicates)) - .collect(); + let mut applicable_candidates: Vec<_> = probes.iter() + .filter(|&probe| self.consider_probe(self_ty, probe, possibly_unsatisfied_predicates)) + .collect(); debug!("applicable_candidates: {:?}", applicable_candidates); if applicable_candidates.len() > 1 { match self.collapse_candidates_to_trait_pick(&applicable_candidates[..]) { - Some(pick) => { return Some(Ok(pick)); } - None => { } + Some(pick) => { + return Some(Ok(pick)); + } + None => {} } } @@ -1041,21 +1033,22 @@ impl<'a, 'gcx, 'tcx> ProbeContext<'a, 'gcx, 'tcx> { return Some(Err(MethodError::Ambiguity(sources))); } - applicable_candidates.pop().map(|probe| { - Ok(probe.to_unadjusted_pick()) - }) + applicable_candidates.pop().map(|probe| Ok(probe.to_unadjusted_pick())) } - fn consider_probe(&self, self_ty: Ty<'tcx>, probe: &Candidate<'tcx>, - possibly_unsatisfied_predicates: &mut Vec>) -> bool { - debug!("consider_probe: self_ty={:?} probe={:?}", - self_ty, - probe); + fn consider_probe(&self, + self_ty: Ty<'tcx>, + probe: &Candidate<'tcx>, + possibly_unsatisfied_predicates: &mut Vec>) + -> bool { + debug!("consider_probe: self_ty={:?} probe={:?}", self_ty, probe); self.probe(|_| { // First check that the self type can be related. - match self.sub_types(false, TypeOrigin::Misc(DUMMY_SP), - self_ty, probe.xform_self_ty) { + match self.sub_types(false, + TypeOrigin::Misc(DUMMY_SP), + self_ty, + probe.xform_self_ty) { Ok(InferOk { obligations, .. }) => { // FIXME(#32730) propagate obligations assert!(obligations.is_empty()) @@ -1093,14 +1086,11 @@ impl<'a, 'gcx, 'tcx> ProbeContext<'a, 'gcx, 'tcx> { // Check whether the impl imposes obligations we have to worry about. let impl_bounds = self.tcx.lookup_predicates(impl_def_id); let impl_bounds = impl_bounds.instantiate(self.tcx, substs); - let traits::Normalized { value: impl_bounds, - obligations: norm_obligations } = + let traits::Normalized { value: impl_bounds, obligations: norm_obligations } = traits::normalize(selcx, cause.clone(), &impl_bounds); // Convert the bounds into obligations. - let obligations = - traits::predicates_for_generics(cause.clone(), - &impl_bounds); + let obligations = traits::predicates_for_generics(cause.clone(), &impl_bounds); debug!("impl_obligations={:?}", obligations); // Evaluate those obligations to see if they might possibly hold. @@ -1136,14 +1126,12 @@ impl<'a, 'gcx, 'tcx> ProbeContext<'a, 'gcx, 'tcx> { /// /// Now imagine the receiver is `Vec<_>`. It doesn't really matter at this time which impl we /// use, so it's ok to just commit to "using the method from the trait Foo". - fn collapse_candidates_to_trait_pick(&self, - probes: &[&Candidate<'tcx>]) - -> Option> { + fn collapse_candidates_to_trait_pick(&self, probes: &[&Candidate<'tcx>]) -> Option> { // Do all probes correspond to the same trait? let container = probes[0].item.container(); match container { ty::TraitContainer(_) => {} - ty::ImplContainer(_) => return None + ty::ImplContainer(_) => return None, } if probes[1..].iter().any(|p| p.item.container() != container) { return None; @@ -1156,7 +1144,7 @@ impl<'a, 'gcx, 'tcx> ProbeContext<'a, 'gcx, 'tcx> { import_id: probes[0].import_id, autoderefs: 0, autoref: None, - unsize: None + unsize: None, }) } @@ -1165,13 +1153,14 @@ impl<'a, 'gcx, 'tcx> ProbeContext<'a, 'gcx, 'tcx> { fn has_applicable_self(&self, item: &ty::ImplOrTraitItem) -> bool { // "fast track" -- check for usage of sugar match *item { - ty::ImplOrTraitItem::MethodTraitItem(ref method) => + ty::ImplOrTraitItem::MethodTraitItem(ref method) => { match method.explicit_self { ty::ExplicitSelfCategory::Static => self.mode == Mode::Path, ty::ExplicitSelfCategory::ByValue | ty::ExplicitSelfCategory::ByReference(..) | ty::ExplicitSelfCategory::ByBox => true, - }, + } + } ty::ImplOrTraitItem::ConstTraitItem(..) => self.mode == Mode::Path, _ => false, } @@ -1191,11 +1180,9 @@ impl<'a, 'gcx, 'tcx> ProbeContext<'a, 'gcx, 'tcx> { item: &ty::ImplOrTraitItem<'tcx>, impl_ty: Ty<'tcx>, substs: &Substs<'tcx>) - -> Ty<'tcx> - { + -> Ty<'tcx> { match item.as_opt_method() { - Some(ref method) => self.xform_method_self_ty(method, impl_ty, - substs), + Some(ref method) => self.xform_method_self_ty(method, impl_ty, substs), None => impl_ty, } } @@ -1204,8 +1191,7 @@ impl<'a, 'gcx, 'tcx> ProbeContext<'a, 'gcx, 'tcx> { method: &Rc>, impl_ty: Ty<'tcx>, substs: &Substs<'tcx>) - -> Ty<'tcx> - { + -> Ty<'tcx> { debug!("xform_self_ty(impl_ty={:?}, self_ty={:?}, substs={:?})", impl_ty, method.fty.sig.0.inputs.get(0), @@ -1218,8 +1204,10 @@ impl<'a, 'gcx, 'tcx> ProbeContext<'a, 'gcx, 'tcx> { // are given do not include type/lifetime parameters for the // method yet. So create fresh variables here for those too, // if there are any. - assert_eq!(substs.types().count(), method.generics.parent_types as usize); - assert_eq!(substs.regions().count(), method.generics.parent_regions as usize); + assert_eq!(substs.types().count(), + method.generics.parent_types as usize); + assert_eq!(substs.regions().count(), + method.generics.parent_regions as usize); if self.mode == Mode::Path { return impl_ty; @@ -1233,7 +1221,9 @@ impl<'a, 'gcx, 'tcx> ProbeContext<'a, 'gcx, 'tcx> { if method.generics.types.is_empty() && method.generics.regions.is_empty() { xform_self_ty.subst(self.tcx, substs) } else { - let substs = Substs::for_item(self.tcx, method.def_id, |def, _| { + let substs = Substs::for_item(self.tcx, + method.def_id, + |def, _| { let i = def.index as usize; if i < substs.params().len() { substs.region_at(i) @@ -1242,7 +1232,8 @@ impl<'a, 'gcx, 'tcx> ProbeContext<'a, 'gcx, 'tcx> { // `impl_self_ty()` for an explanation. self.tcx.mk_region(ty::ReErased) } - }, |def, cur_substs| { + }, + |def, cur_substs| { let i = def.index as usize; if i < substs.params().len() { substs.type_at(i) @@ -1255,13 +1246,11 @@ impl<'a, 'gcx, 'tcx> ProbeContext<'a, 'gcx, 'tcx> { } /// Get the type of an impl and generate substitutions with placeholders. - fn impl_ty_and_substs(&self, - impl_def_id: DefId) - -> (Ty<'tcx>, &'tcx Substs<'tcx>) - { + fn impl_ty_and_substs(&self, impl_def_id: DefId) -> (Ty<'tcx>, &'tcx Substs<'tcx>) { let impl_ty = self.tcx.lookup_item_type(impl_def_id).ty; - let substs = Substs::for_item(self.tcx, impl_def_id, + let substs = Substs::for_item(self.tcx, + impl_def_id, |_, _| self.tcx.mk_region(ty::ReErased), |_, _| self.next_ty_var()); @@ -1287,16 +1276,14 @@ impl<'a, 'gcx, 'tcx> ProbeContext<'a, 'gcx, 'tcx> { /// and/or tracking the substitution and /// so forth. fn erase_late_bound_regions(&self, value: &ty::Binder) -> T - where T : TypeFoldable<'tcx> + where T: TypeFoldable<'tcx> { self.tcx.erase_late_bound_regions(value) } /// Find item with name `item_name` defined in impl/trait `def_id` /// and return it, or `None`, if no such item was defined there. - fn impl_or_trait_item(&self, def_id: DefId) - -> Option> - { + fn impl_or_trait_item(&self, def_id: DefId) -> Option> { self.fcx.impl_or_trait_item(def_id, self.item_name) } } @@ -1307,9 +1294,7 @@ impl<'tcx> Candidate<'tcx> { item: self.item.clone(), kind: match self.kind { InherentImplCandidate(..) => InherentImplPick, - ExtensionImplCandidate(def_id, ..) => { - ExtensionImplPick(def_id) - } + ExtensionImplCandidate(def_id, ..) => ExtensionImplPick(def_id), ObjectCandidate => ObjectPick, TraitCandidate => TraitPick, WhereClauseCandidate(ref trait_ref) => { @@ -1326,15 +1311,13 @@ impl<'tcx> Candidate<'tcx> { import_id: self.import_id, autoderefs: 0, autoref: None, - unsize: None + unsize: None, } } fn to_source(&self) -> CandidateSource { match self.kind { - InherentImplCandidate(..) => { - ImplSource(self.item.container().id()) - } + InherentImplCandidate(..) => ImplSource(self.item.container().id()), ExtensionImplCandidate(def_id, ..) => ImplSource(def_id), ObjectCandidate | TraitCandidate | diff --git a/src/librustc_typeck/check/method/suggest.rs b/src/librustc_typeck/check/method/suggest.rs index 34bcd2ba04..32bf839a4e 100644 --- a/src/librustc_typeck/check/method/suggest.rs +++ b/src/librustc_typeck/check/method/suggest.rs @@ -13,15 +13,14 @@ use CrateCtxt; -use check::{FnCtxt}; +use check::FnCtxt; use rustc::hir::map as hir_map; use rustc::ty::{self, Ty, ToPolyTraitRef, ToPredicate, TypeFoldable}; use hir::def::Def; use hir::def_id::{CRATE_DEF_INDEX, DefId}; use middle::lang_items::FnOnceTraitLangItem; -use rustc::ty::subst::Substs; use rustc::traits::{Obligation, SelectionContext}; -use util::nodemap::{FnvHashSet}; +use util::nodemap::FnvHashSet; use syntax::ast; use errors::DiagnosticBuilder; @@ -43,25 +42,26 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { match ty.sty { // Not all of these (e.g. unsafe fns) implement FnOnce // so we look for these beforehand - ty::TyClosure(..) | ty::TyFnDef(..) | ty::TyFnPtr(_) => true, + ty::TyClosure(..) | + ty::TyFnDef(..) | + ty::TyFnPtr(_) => true, // If it's not a simple function, look for things which implement FnOnce _ => { let fn_once = match tcx.lang_items.require(FnOnceTraitLangItem) { Ok(fn_once) => fn_once, - Err(..) => return false + Err(..) => return false, }; - self.autoderef(span, ty).any(|(ty, _)| self.probe(|_| { - let fn_once_substs = - Substs::new_trait(tcx, ty, &[self.next_ty_var()]); - let trait_ref = ty::TraitRef::new(fn_once, fn_once_substs); - let poly_trait_ref = trait_ref.to_poly_trait_ref(); - let obligation = Obligation::misc(span, - self.body_id, - poly_trait_ref - .to_predicate()); - SelectionContext::new(self).evaluate_obligation(&obligation) - })) + self.autoderef(span, ty).any(|(ty, _)| { + self.probe(|_| { + let fn_once_substs = tcx.mk_substs_trait(ty, &[self.next_ty_var()]); + let trait_ref = ty::TraitRef::new(fn_once, fn_once_substs); + let poly_trait_ref = trait_ref.to_poly_trait_ref(); + let obligation = + Obligation::misc(span, self.body_id, poly_trait_ref.to_predicate()); + SelectionContext::new(self).evaluate_obligation(&obligation) + }) + }) } } } @@ -71,15 +71,13 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { rcvr_ty: Ty<'tcx>, item_name: ast::Name, rcvr_expr: Option<&hir::Expr>, - error: MethodError<'tcx>) - { + error: MethodError<'tcx>) { // avoid suggestions when we don't know what's going on. if rcvr_ty.references_error() { - return + return; } - let report_candidates = |err: &mut DiagnosticBuilder, - mut sources: Vec| { + let report_candidates = |err: &mut DiagnosticBuilder, mut sources: Vec| { sources.sort(); sources.dedup(); @@ -93,15 +91,18 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { // the impl, if local to crate (item may be defaulted), else nothing. let item = self.impl_or_trait_item(impl_did, item_name) .or_else(|| { - self.impl_or_trait_item( - self.tcx.impl_trait_ref(impl_did).unwrap().def_id, - - item_name - ) - }).unwrap(); - let note_span = self.tcx.map.span_if_local(item.def_id()).or_else(|| { - self.tcx.map.span_if_local(impl_did) - }); + self.impl_or_trait_item(self.tcx + .impl_trait_ref(impl_did) + .unwrap() + .def_id, + + item_name) + }) + .unwrap(); + let note_span = self.tcx + .map + .span_if_local(item.def_id()) + .or_else(|| self.tcx.map.span_if_local(impl_did)); let impl_ty = self.impl_self_ty(span, impl_did).ty; @@ -128,7 +129,8 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { CandidateSource::TraitSource(trait_did) => { let item = self.impl_or_trait_item(trait_did, item_name).unwrap(); let item_span = self.tcx.map.def_id_span(item.def_id(), span); - span_note!(err, item_span, + span_note!(err, + item_span, "candidate #{} is defined in the trait `{}`", idx + 1, self.tcx.item_path_str(trait_did)); @@ -144,20 +146,22 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { MethodError::NoMatch(NoMatchData { static_candidates: static_sources, unsatisfied_predicates, out_of_scope_traits, - mode, .. }) => { + mode, + .. }) => { let tcx = self.tcx; - let mut err = self.type_error_struct( - span, - |actual| { - format!("no {} named `{}` found for type `{}` \ - in the current scope", - if mode == Mode::MethodCall { "method" } - else { "associated item" }, - item_name, - actual) - }, - rcvr_ty); + let mut err = self.type_error_struct(span, + |actual| { + format!("no {} named `{}` found for type `{}` in the current scope", + if mode == Mode::MethodCall { + "method" + } else { + "associated item" + }, + item_name, + actual) + }, + rcvr_ty); // If the method name is the name of a field with a function or closure type, // give a helping note that it has to be called as (x.f)(...). @@ -165,27 +169,30 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { for (ty, _) in self.autoderef(span, rcvr_ty) { match ty.sty { ty::TyAdt(def, substs) if !def.is_enum() => { - if let Some(field) = def.struct_variant(). - find_field_named(item_name) { + if let Some(field) = def.struct_variant() + .find_field_named(item_name) { let snippet = tcx.sess.codemap().span_to_snippet(expr.span); let expr_string = match snippet { Ok(expr_string) => expr_string, - _ => "s".into() // Default to a generic placeholder for the - // expression when we can't generate a - // string snippet + _ => "s".into(), // Default to a generic placeholder for the + // expression when we can't generate a + // string snippet }; let field_ty = field.ty(tcx, substs); if self.is_fn_ty(&field_ty, span) { - err.span_note(span, &format!( - "use `({0}.{1})(...)` if you meant to call the \ - function stored in the `{1}` field", - expr_string, item_name)); + err.span_note(span, + &format!("use `({0}.{1})(...)` if you \ + meant to call the function \ + stored in the `{1}` field", + expr_string, + item_name)); } else { - err.span_note(span, &format!( - "did you mean to write `{0}.{1}`?", - expr_string, item_name)); + err.span_note(span, + &format!("did you mean to write `{0}.{1}`?", + expr_string, + item_name)); } break; } @@ -204,10 +211,9 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { } if let Some(expr) = rcvr_expr { - if let Ok (expr_string) = tcx.sess.codemap().span_to_snippet(expr.span) { + if let Ok(expr_string) = tcx.sess.codemap().span_to_snippet(expr.span) { report_function!(expr.span, expr_string); - } - else if let Expr_::ExprPath(_, path) = expr.node.clone() { + } else if let Expr_::ExprPath(_, path) = expr.node.clone() { if let Some(segment) = path.segments.last() { report_function!(expr.span, segment.name); } @@ -216,34 +222,36 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { } if !static_sources.is_empty() { - err.note( - "found the following associated functions; to be used as \ - methods, functions must have a `self` parameter"); + err.note("found the following associated functions; to be used as methods, \ + functions must have a `self` parameter"); report_candidates(&mut err, static_sources); } if !unsatisfied_predicates.is_empty() { let bound_list = unsatisfied_predicates.iter() - .map(|p| format!("`{} : {}`", - p.self_ty(), - p)) + .map(|p| format!("`{} : {}`", p.self_ty(), p)) .collect::>() .join(", "); - err.note( - &format!("the method `{}` exists but the \ - following trait bounds were not satisfied: {}", - item_name, - bound_list)); + err.note(&format!("the method `{}` exists but the following trait bounds \ + were not satisfied: {}", + item_name, + bound_list)); } - self.suggest_traits_to_import(&mut err, span, rcvr_ty, item_name, - rcvr_expr, out_of_scope_traits); + self.suggest_traits_to_import(&mut err, + span, + rcvr_ty, + item_name, + rcvr_expr, + out_of_scope_traits); err.emit(); } MethodError::Ambiguity(sources) => { - let mut err = struct_span_err!(self.sess(), span, E0034, + let mut err = struct_span_err!(self.sess(), + span, + E0034, "multiple applicable items in scope"); err.span_label(span, &format!("multiple `{}` found", item_name)); @@ -255,11 +263,12 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { let msg = format!("the `{}` method from the `{}` trait cannot be explicitly \ invoked on this closure as we have not yet inferred what \ kind of closure it is", - item_name, - self.tcx.item_path_str(trait_def_id)); + item_name, + self.tcx.item_path_str(trait_def_id)); let msg = if let Some(callee) = rcvr_expr { format!("{}; use overloaded call notation instead (e.g., `{}()`)", - msg, pprust::expr_to_string(callee)) + msg, + pprust::expr_to_string(callee)) } else { msg }; @@ -279,18 +288,24 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { rcvr_ty: Ty<'tcx>, item_name: ast::Name, rcvr_expr: Option<&hir::Expr>, - valid_out_of_scope_traits: Vec) - { + valid_out_of_scope_traits: Vec) { if !valid_out_of_scope_traits.is_empty() { let mut candidates = valid_out_of_scope_traits; candidates.sort(); candidates.dedup(); - let msg = format!( - "items from traits can only be used if the trait is in scope; \ - the following {traits_are} implemented but not in scope, \ - perhaps add a `use` for {one_of_them}:", - traits_are = if candidates.len() == 1 {"trait is"} else {"traits are"}, - one_of_them = if candidates.len() == 1 {"it"} else {"one of them"}); + let msg = format!("items from traits can only be used if the trait is in scope; the \ + following {traits_are} implemented but not in scope, perhaps add \ + a `use` for {one_of_them}:", + traits_are = if candidates.len() == 1 { + "trait is" + } else { + "traits are" + }, + one_of_them = if candidates.len() == 1 { + "it" + } else { + "one of them" + }); err.help(&msg[..]); @@ -303,7 +318,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { if candidates.len() > limit { err.note(&format!("and {} others", candidates.len() - limit)); } - return + return; } let type_is_local = self.type_derefs_to_local(span, rcvr_ty, rcvr_expr); @@ -319,8 +334,8 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { // this isn't perfect (that is, there are cases when // implementing a trait would be legal but is rejected // here). - (type_is_local || info.def_id.is_local()) - && self.impl_or_trait_item(info.def_id, item_name).is_some() + (type_is_local || info.def_id.is_local()) && + self.impl_or_trait_item(info.def_id, item_name).is_some() }) .collect::>(); @@ -332,13 +347,20 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { // FIXME #21673 this help message could be tuned to the case // of a type parameter: suggest adding a trait bound rather // than implementing. - let msg = format!( - "items from traits can only be used if the trait is implemented and in scope; \ - the following {traits_define} an item `{name}`, \ - perhaps you need to implement {one_of_them}:", - traits_define = if candidates.len() == 1 {"trait defines"} else {"traits define"}, - one_of_them = if candidates.len() == 1 {"it"} else {"one of them"}, - name = item_name); + let msg = format!("items from traits can only be used if the trait is implemented \ + and in scope; the following {traits_define} an item `{name}`, \ + perhaps you need to implement {one_of_them}:", + traits_define = if candidates.len() == 1 { + "trait defines" + } else { + "traits define" + }, + one_of_them = if candidates.len() == 1 { + "it" + } else { + "one of them" + }, + name = item_name); err.help(&msg[..]); @@ -355,7 +377,8 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { fn type_derefs_to_local(&self, span: Span, rcvr_ty: Ty<'tcx>, - rcvr_expr: Option<&hir::Expr>) -> bool { + rcvr_expr: Option<&hir::Expr>) + -> bool { fn is_local(ty: Ty) -> bool { match ty.sty { ty::TyAdt(def, _) => def.did.is_local(), @@ -368,7 +391,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { // non-local (there are "edge" cases, e.g. (LocalType,), but // the noise from these sort of types is usually just really // annoying, rather than any sort of help). - _ => false + _ => false, } } @@ -391,9 +414,7 @@ pub struct TraitInfo { impl TraitInfo { fn new(def_id: DefId) -> TraitInfo { - TraitInfo { - def_id: def_id, - } + TraitInfo { def_id: def_id } } } impl PartialEq for TraitInfo { @@ -403,7 +424,9 @@ impl PartialEq for TraitInfo { } impl Eq for TraitInfo {} impl PartialOrd for TraitInfo { - fn partial_cmp(&self, other: &TraitInfo) -> Option { Some(self.cmp(other)) } + fn partial_cmp(&self, other: &TraitInfo) -> Option { + Some(self.cmp(other)) + } } impl Ord for TraitInfo { fn cmp(&self, other: &TraitInfo) -> Ordering { @@ -426,7 +449,7 @@ pub fn all_traits<'a>(ccx: &'a CrateCtxt) -> AllTraits<'a> { // Crate-local: // // meh. - struct Visitor<'a, 'tcx:'a> { + struct Visitor<'a, 'tcx: 'a> { map: &'a hir_map::Map<'tcx>, traits: &'a mut AllTraitsVec, } @@ -443,7 +466,7 @@ pub fn all_traits<'a>(ccx: &'a CrateCtxt) -> AllTraits<'a> { } ccx.tcx.map.krate().visit_all_items(&mut Visitor { map: &ccx.tcx.map, - traits: &mut traits + traits: &mut traits, }); // Cross-crate: @@ -451,27 +474,29 @@ pub fn all_traits<'a>(ccx: &'a CrateCtxt) -> AllTraits<'a> { fn handle_external_def(ccx: &CrateCtxt, traits: &mut AllTraitsVec, external_mods: &mut FnvHashSet, - def_id: DefId) { - match ccx.tcx.sess.cstore.describe_def(def_id) { - Some(Def::Trait(_)) => { + def: Def) { + let def_id = def.def_id(); + match def { + Def::Trait(..) => { traits.push(TraitInfo::new(def_id)); } - Some(Def::Mod(_)) => { + Def::Mod(..) => { if !external_mods.insert(def_id) { return; } for child in ccx.tcx.sess.cstore.item_children(def_id) { - handle_external_def(ccx, traits, external_mods, child.def_id) + handle_external_def(ccx, traits, external_mods, child.def) } } _ => {} } } for cnum in ccx.tcx.sess.cstore.crates() { - handle_external_def(ccx, &mut traits, &mut external_mods, DefId { + let def_id = DefId { krate: cnum, - index: CRATE_DEF_INDEX - }); + index: CRATE_DEF_INDEX, + }; + handle_external_def(ccx, &mut traits, &mut external_mods, Def::Mod(def_id)); } *ccx.all_traits.borrow_mut() = Some(traits); @@ -481,13 +506,13 @@ pub fn all_traits<'a>(ccx: &'a CrateCtxt) -> AllTraits<'a> { assert!(borrow.is_some()); AllTraits { borrow: borrow, - idx: 0 + idx: 0, } } pub struct AllTraits<'a> { borrow: cell::Ref<'a, Option>, - idx: usize + idx: usize, } impl<'a> Iterator for AllTraits<'a> { diff --git a/src/librustc_typeck/check/mod.rs b/src/librustc_typeck/check/mod.rs index 8151849613..d8314bd6c2 100644 --- a/src/librustc_typeck/check/mod.rs +++ b/src/librustc_typeck/check/mod.rs @@ -83,11 +83,11 @@ use self::TupleArgumentsFlag::*; use astconv::{AstConv, ast_region_to_region, PathParamMode}; use dep_graph::DepNode; use fmt_macros::{Parser, Piece, Position}; -use hir::def::{Def, PathResolution}; +use hir::def::{Def, CtorKind, PathResolution}; use hir::def_id::{DefId, LOCAL_CRATE}; use hir::pat_util; use rustc::infer::{self, InferCtxt, InferOk, TypeOrigin, TypeTrace, type_variable}; -use rustc::ty::subst::{Subst, Substs}; +use rustc::ty::subst::{Kind, Subst, Substs}; use rustc::traits::{self, Reveal}; use rustc::ty::{ParamTy, ParameterEnvironment}; use rustc::ty::{LvaluePreference, NoPreference, PreferMutLvalue}; @@ -407,22 +407,26 @@ impl<'a, 'gcx, 'tcx> InheritedBuilder<'a, 'gcx, 'tcx> { where F: for<'b> FnOnce(Inherited<'b, 'gcx, 'tcx>) -> R { let ccx = self.ccx; - self.infcx.enter(|infcx| { - f(Inherited { - ccx: ccx, - infcx: infcx, - fulfillment_cx: RefCell::new(traits::FulfillmentContext::new()), - locals: RefCell::new(NodeMap()), - deferred_call_resolutions: RefCell::new(DefIdMap()), - deferred_cast_checks: RefCell::new(Vec::new()), - anon_types: RefCell::new(DefIdMap()), - deferred_obligations: RefCell::new(Vec::new()), - }) - }) + self.infcx.enter(|infcx| f(Inherited::new(ccx, infcx))) } } impl<'a, 'gcx, 'tcx> Inherited<'a, 'gcx, 'tcx> { + pub fn new(ccx: &'a CrateCtxt<'a, 'gcx>, + infcx: InferCtxt<'a, 'gcx, 'tcx>) + -> Self { + Inherited { + ccx: ccx, + infcx: infcx, + fulfillment_cx: RefCell::new(traits::FulfillmentContext::new()), + locals: RefCell::new(NodeMap()), + deferred_call_resolutions: RefCell::new(DefIdMap()), + deferred_cast_checks: RefCell::new(Vec::new()), + anon_types: RefCell::new(DefIdMap()), + deferred_obligations: RefCell::new(Vec::new()), + } + } + fn normalize_associated_types_in(&self, span: Span, body_id: ast::NodeId, @@ -450,7 +454,7 @@ impl<'a, 'tcx> Visitor<'tcx> for CheckItemTypesVisitor<'a, 'tcx> { fn visit_ty(&mut self, t: &'tcx hir::Ty) { match t.node { - hir::TyFixedLengthVec(_, ref expr) => { + hir::TyArray(_, ref expr) => { check_const_with_type(self.ccx, &expr, self.ccx.tcx.types.usize, expr.id); } _ => {} @@ -531,13 +535,16 @@ pub fn check_drop_impls(ccx: &CrateCtxt) -> CompileResult { fn check_bare_fn<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>, decl: &'tcx hir::FnDecl, body: &'tcx hir::Block, - fn_id: ast::NodeId) { + fn_id: ast::NodeId, + span: Span) { let raw_fty = ccx.tcx.lookup_item_type(ccx.tcx.map.local_def_id(fn_id)).ty; let fn_ty = match raw_fty.sty { ty::TyFnDef(.., f) => f, _ => span_bug!(body.span, "check_bare_fn: function type expected") }; + check_abi(ccx, span, fn_ty.abi); + ccx.inherited(fn_id).enter(|inh| { // Compute the fty from point of view of inside fn. let fn_scope = inh.tcx.region_maps.call_site_extent(fn_id, body.id); @@ -561,6 +568,13 @@ fn check_bare_fn<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>, }); } +fn check_abi<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>, span: Span, abi: Abi) { + if !ccx.tcx.sess.target.target.is_abi_supported(abi) { + struct_span_err!(ccx.tcx.sess, span, E0570, + "The ABI `{}` is not supported for the current target", abi).emit() + } +} + struct GatherLocalsVisitor<'a, 'gcx: 'a+'tcx, 'tcx: 'a> { fcx: &'a FnCtxt<'a, 'gcx, 'tcx> } @@ -626,7 +640,7 @@ impl<'a, 'gcx, 'tcx> Visitor<'gcx> for GatherLocalsVisitor<'a, 'gcx, 'tcx> { // need to record the type for that node fn visit_ty(&mut self, t: &'gcx hir::Ty) { match t.node { - hir::TyFixedLengthVec(ref ty, ref count_expr) => { + hir::TyArray(ref ty, ref count_expr) => { self.visit_ty(&ty); self.fcx.check_expr_with_hint(&count_expr, self.fcx.tcx.types.usize); } @@ -742,17 +756,14 @@ pub fn check_item_type<'a,'tcx>(ccx: &CrateCtxt<'a,'tcx>, it: &'tcx hir::Item) { hir::ItemImpl(.., ref impl_items) => { debug!("ItemImpl {} with id {}", it.name, it.id); let impl_def_id = ccx.tcx.map.local_def_id(it.id); - match ccx.tcx.impl_trait_ref(impl_def_id) { - Some(impl_trait_ref) => { - check_impl_items_against_trait(ccx, - it.span, - impl_def_id, - &impl_trait_ref, - impl_items); - let trait_def_id = impl_trait_ref.def_id; - check_on_unimplemented(ccx, trait_def_id, it); - } - None => { } + if let Some(impl_trait_ref) = ccx.tcx.impl_trait_ref(impl_def_id) { + check_impl_items_against_trait(ccx, + it.span, + impl_def_id, + &impl_trait_ref, + impl_items); + let trait_def_id = impl_trait_ref.def_id; + check_on_unimplemented(ccx, trait_def_id, it); } } hir::ItemTrait(..) => { @@ -766,10 +777,12 @@ pub fn check_item_type<'a,'tcx>(ccx: &CrateCtxt<'a,'tcx>, it: &'tcx hir::Item) { check_union(ccx, it.id, it.span); } hir::ItemTy(_, ref generics) => { - let pty_ty = ccx.tcx.node_id_to_type(it.id); + let pty_ty = ccx.tcx.tables().node_id_to_type(it.id); check_bounds_are_used(ccx, generics, pty_ty); } hir::ItemForeignMod(ref m) => { + check_abi(ccx, it.span, m.abi); + if m.abi == Abi::RustIntrinsic { for item in &m.items { intrinsic::check_intrinsic_type(ccx, item); @@ -807,7 +820,7 @@ pub fn check_item_body<'a,'tcx>(ccx: &CrateCtxt<'a,'tcx>, it: &'tcx hir::Item) { let _indenter = indenter(); match it.node { hir::ItemFn(ref decl, .., ref body) => { - check_bare_fn(ccx, &decl, &body, it.id); + check_bare_fn(ccx, &decl, &body, it.id, it.span); } hir::ItemImpl(.., ref impl_items) => { debug!("ItemImpl {} with id {}", it.name, it.id); @@ -818,7 +831,7 @@ pub fn check_item_body<'a,'tcx>(ccx: &CrateCtxt<'a,'tcx>, it: &'tcx hir::Item) { check_const(ccx, &expr, impl_item.id) } hir::ImplItemKind::Method(ref sig, ref body) => { - check_bare_fn(ccx, &sig.decl, body, impl_item.id); + check_bare_fn(ccx, &sig.decl, body, impl_item.id, impl_item.span); } hir::ImplItemKind::Type(_) => { // Nothing to do here. @@ -833,7 +846,7 @@ pub fn check_item_body<'a,'tcx>(ccx: &CrateCtxt<'a,'tcx>, it: &'tcx hir::Item) { check_const(ccx, &expr, trait_item.id) } hir::MethodTraitItem(ref sig, Some(ref body)) => { - check_bare_fn(ccx, &sig.decl, body, trait_item.id); + check_bare_fn(ccx, &sig.decl, body, trait_item.id, trait_item.span); } hir::MethodTraitItem(_, None) | hir::ConstTraitItem(_, None) | @@ -1015,13 +1028,26 @@ fn check_impl_items_against_trait<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>, let trait_span = tcx.map.span_if_local(ty_trait_item.def_id()); if let &ty::MethodTraitItem(ref trait_method) = ty_trait_item { + let err_count = tcx.sess.err_count(); compare_impl_method(ccx, &impl_method, impl_item.span, body.id, &trait_method, &impl_trait_ref, - trait_span); + trait_span, + true); // start with old-broken-mode + if err_count == tcx.sess.err_count() { + // old broken mode did not report an error. Try with the new mode. + compare_impl_method(ccx, + &impl_method, + impl_item.span, + body.id, + &trait_method, + &impl_trait_ref, + trait_span, + false); // use the new mode + } } else { let mut err = struct_span_err!(tcx.sess, impl_item.span, E0324, "item `{}` is an associated method, \ @@ -1179,7 +1205,7 @@ fn check_representable<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, sp: Span, item_id: ast::NodeId) -> bool { - let rty = tcx.node_id_to_type(item_id); + let rty = tcx.tables().node_id_to_type(item_id); // Check that it is possible to represent this type. This call identifies // (1) types that contain themselves and (2) types that contain a different @@ -1198,7 +1224,7 @@ fn check_representable<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, } pub fn check_simd<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, sp: Span, id: ast::NodeId) { - let t = tcx.node_id_to_type(id); + let t = tcx.tables().node_id_to_type(id); match t.sty { ty::TyAdt(def, substs) if def.is_struct() => { let fields = &def.struct_variant().fields; @@ -1361,7 +1387,7 @@ impl<'a, 'gcx, 'tcx> AstConv<'gcx, 'tcx> for FnCtxt<'a, 'gcx, 'tcx> { fn ty_infer_for_def(&self, ty_param_def: &ty::TypeParameterDef<'tcx>, - substs: &Substs<'tcx>, + substs: &[Kind<'tcx>], span: Span) -> Ty<'tcx> { self.type_var_for_def(span, ty_param_def, substs) } @@ -1555,20 +1581,21 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { pub fn write_autoderef_adjustment(&self, node_id: ast::NodeId, - derefs: usize) { - self.write_adjustment( - node_id, - adjustment::AdjustDerefRef(adjustment::AutoDerefRef { + derefs: usize, + adjusted_ty: Ty<'tcx>) { + self.write_adjustment(node_id, adjustment::Adjustment { + kind: adjustment::Adjust::DerefRef { autoderefs: derefs, autoref: None, - unsize: None - }) - ); + unsize: false + }, + target: adjusted_ty + }); } pub fn write_adjustment(&self, node_id: ast::NodeId, - adj: adjustment::AutoAdjustment<'tcx>) { + adj: adjustment::Adjustment<'tcx>) { debug!("write_adjustment(node_id={}, adj={:?})", node_id, adj); if adj.is_identity() { @@ -1677,41 +1704,6 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { cause) } - /// Instantiates the type in `did` with the generics in `path` and returns - /// it (registering the necessary trait obligations along the way). - /// - /// Note that this function is only intended to be used with type-paths, - /// not with value-paths. - pub fn instantiate_type_path(&self, - did: DefId, - path: &hir::Path, - node_id: ast::NodeId) - -> Ty<'tcx> { - debug!("instantiate_type_path(did={:?}, path={:?})", did, path); - let mut ty = self.tcx.lookup_item_type(did).ty; - if ty.is_fn() { - // Tuple variants have fn type even in type namespace, extract true variant type from it - ty = self.tcx.no_late_bound_regions(&ty.fn_ret()).unwrap(); - } - let type_predicates = self.tcx.lookup_predicates(did); - let substs = AstConv::ast_path_substs_for_ty(self, self, - path.span, - PathParamMode::Optional, - did, - path.segments.last().unwrap()); - debug!("instantiate_type_path: ty={:?} substs={:?}", ty, substs); - let bounds = self.instantiate_bounds(path.span, substs, &type_predicates); - let cause = traits::ObligationCause::new(path.span, self.body_id, - traits::ItemObligation(did)); - self.add_obligations_for_parameters(cause, &bounds); - - let ty_substituted = self.instantiate_type_scheme(path.span, substs, &ty); - self.write_substs(node_id, ty::ItemSubsts { - substs: substs - }); - ty_substituted - } - pub fn write_nil(&self, node_id: ast::NodeId) { self.write_ty(node_id, self.tcx.mk_nil()); } @@ -1769,21 +1761,6 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { t } - /// Apply `adjustment` to the type of `expr` - pub fn adjust_expr_ty(&self, - expr: &hir::Expr, - adjustment: Option<&adjustment::AutoAdjustment<'tcx>>) - -> Ty<'tcx> - { - let raw_ty = self.node_ty(expr.id); - let raw_ty = self.shallow_resolve(raw_ty); - let resolve_ty = |ty: Ty<'tcx>| self.resolve_type_vars_if_possible(&ty); - raw_ty.adjust(self.tcx, expr.span, expr.id, adjustment, |method_call| { - self.tables.borrow().method_map.get(&method_call) - .map(|method| resolve_ty(method.ty)) - }) - } - pub fn node_ty(&self, id: ast::NodeId) -> Ty<'tcx> { match self.tables.borrow().node_types.get(&id) { Some(&t) => t, @@ -1812,9 +1789,8 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { f: F) where F: FnOnce(&ty::ItemSubsts<'tcx>), { - match self.tables.borrow().item_substs.get(&id) { - Some(s) => { f(s) } - None => { } + if let Some(s) = self.tables.borrow().item_substs.get(&id) { + f(s); } } @@ -2321,7 +2297,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { debug!("try_index_step: success, using built-in indexing"); // If we had `[T; N]`, we should've caught it before unsizing to `[T]`. assert!(!unsize); - self.write_autoderef_adjustment(base_expr.id, autoderefs); + self.write_autoderef_adjustment(base_expr.id, autoderefs, adjusted_ty); return Some((tcx.types.usize, ty)); } _ => {} @@ -2380,7 +2356,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { let err_inputs = match tuple_arguments { DontTupleArguments => err_inputs, - TupleArguments => vec![self.tcx.mk_tup(err_inputs)], + TupleArguments => vec![self.tcx.intern_tup(&err_inputs[..])], }; self.check_argument_types(sp, &err_inputs[..], &[], args_no_rcvr, @@ -2432,6 +2408,21 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { let mut expected_arg_tys = expected_arg_tys; let expected_arg_count = fn_inputs.len(); + let sp_args = if args.len() > 0 { + let (first, args) = args.split_at(1); + let mut sp_tmp = first[0].span; + for arg in args { + let sp_opt = self.sess().codemap().merge_spans(sp_tmp, arg.span); + if ! sp_opt.is_some() { + break; + } + sp_tmp = sp_opt.unwrap(); + }; + sp_tmp + } else { + sp + }; + fn parameter_count_error<'tcx>(sess: &Session, sp: Span, fn_inputs: &[Ty<'tcx>], expected_count: usize, arg_count: usize, error_code: &str, variadic: bool) { @@ -2464,7 +2455,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { let tuple_type = self.structurally_resolved_type(sp, fn_inputs[0]); match tuple_type.sty { ty::TyTuple(arg_types) if arg_types.len() != args.len() => { - parameter_count_error(tcx.sess, sp, fn_inputs, arg_types.len(), args.len(), + parameter_count_error(tcx.sess, sp_args, fn_inputs, arg_types.len(), args.len(), "E0057", false); expected_arg_tys = &[]; self.err_args(args.len()) @@ -2493,14 +2484,14 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { if supplied_arg_count >= expected_arg_count { fn_inputs.to_vec() } else { - parameter_count_error(tcx.sess, sp, fn_inputs, expected_arg_count, + parameter_count_error(tcx.sess, sp_args, fn_inputs, expected_arg_count, supplied_arg_count, "E0060", true); expected_arg_tys = &[]; self.err_args(supplied_arg_count) } } else { - parameter_count_error(tcx.sess, sp, fn_inputs, expected_arg_count, supplied_arg_count, - "E0061", false); + parameter_count_error(tcx.sess, sp_args, fn_inputs, expected_arg_count, + supplied_arg_count, "E0061", false); expected_arg_tys = &[]; self.err_args(supplied_arg_count) }; @@ -2862,9 +2853,11 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { // In case we did perform an adjustment, we have to update // the type of the block, because old trans still uses it. - let adj = self.tables.borrow().adjustments.get(&then.id).cloned(); - if res.is_ok() && adj.is_some() { - self.write_ty(then_blk.id, self.adjust_expr_ty(then, adj.as_ref())); + if res.is_ok() { + let adj = self.tables.borrow().adjustments.get(&then.id).cloned(); + if let Some(adj) = adj { + self.write_ty(then_blk.id, adj.target); + } } res @@ -2925,7 +2918,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { let field_ty = self.field_ty(expr.span, field, substs); if field.vis.is_accessible_from(self.body_id, &self.tcx().map) { autoderef.finalize(lvalue_pref, Some(base)); - self.write_autoderef_adjustment(base.id, autoderefs); + self.write_autoderef_adjustment(base.id, autoderefs, base_t); return field_ty; } private_candidate = Some((base_def.did, field_ty)); @@ -2959,18 +2952,20 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { .emit(); self.tcx().types.err } else { - let mut err = self.type_error_struct(expr.span, |actual| { - format!("attempted access of field `{}` on type `{}`, \ - but no field with that name was found", + let mut err = self.type_error_struct(field.span, |actual| { + format!("no field `{}` on type `{}`", field.node, actual) }, expr_t); match expr_t.sty { ty::TyAdt(def, _) if !def.is_enum() => { if let Some(suggested_field_name) = Self::suggest_field_name(def.struct_variant(), field, vec![]) { - err.span_help(field.span, - &format!("did you mean `{}`?", suggested_field_name)); - }; + err.span_label(field.span, + &format!("did you mean `{}`?", suggested_field_name)); + } else { + err.span_label(field.span, + &format!("unknown field")); + }; } ty::TyRawPtr(..) => { err.note(&format!("`{0}` is a native pointer; perhaps you need to deref with \ @@ -3018,7 +3013,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { while let Some((base_t, autoderefs)) = autoderef.next() { let field = match base_t.sty { ty::TyAdt(base_def, substs) if base_def.is_struct() => { - tuple_like = base_def.struct_variant().kind == ty::VariantKind::Tuple; + tuple_like = base_def.struct_variant().ctor_kind == CtorKind::Fn; if !tuple_like { continue } debug!("tuple struct named {:?}", base_t); @@ -3041,7 +3036,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { if let Some(field_ty) = field { autoderef.finalize(lvalue_pref, Some(base)); - self.write_autoderef_adjustment(base.id, autoderefs); + self.write_autoderef_adjustment(base.id, autoderefs, base_t); return field_ty; } } @@ -3226,47 +3221,65 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { } pub fn check_struct_path(&self, - path: &hir::Path, - node_id: ast::NodeId, - span: Span) - -> Option<(ty::VariantDef<'tcx>, Ty<'tcx>)> { - let def = self.finish_resolving_struct_path(path, node_id, span); + path: &hir::Path, + node_id: ast::NodeId) + -> Option<(ty::VariantDef<'tcx>, Ty<'tcx>)> { + let (def, ty) = self.finish_resolving_struct_path(path, node_id); let variant = match def { Def::Err => { self.set_tainted_by_errors(); return None; } - Def::Variant(did) => { - let type_did = self.tcx.parent_def_id(did).unwrap(); - Some((type_did, self.tcx.expect_variant_def(def))) - } - Def::Struct(type_did) | Def::Union(type_did) => { - Some((type_did, self.tcx.expect_variant_def(def))) + Def::Variant(..) => { + match ty.sty { + ty::TyAdt(adt, substs) => { + Some((adt.variant_of_def(def), adt.did, substs)) + } + _ => bug!("unexpected type: {:?}", ty.sty) + } } - Def::TyAlias(did) => { - match self.tcx.opt_lookup_item_type(did).map(|scheme| &scheme.ty.sty) { - Some(&ty::TyAdt(adt, _)) if !adt.is_enum() => { - Some((did, adt.struct_variant())) + Def::Struct(..) | Def::Union(..) | Def::TyAlias(..) | + Def::AssociatedTy(..) | Def::SelfTy(..) => { + match def { + Def::AssociatedTy(..) | Def::SelfTy(..) + if !self.tcx.sess.features.borrow().more_struct_aliases => { + emit_feature_err(&self.tcx.sess.parse_sess, + "more_struct_aliases", path.span, GateIssue::Language, + "`Self` and associated types in struct \ + expressions and patterns are unstable"); + } + _ => {} + } + match ty.sty { + ty::TyAdt(adt, substs) if !adt.is_enum() => { + Some((adt.struct_variant(), adt.did, substs)) } _ => None, } } - _ => None + _ => bug!("unexpected definition: {:?}", def) }; - if let Some((def_id, variant)) = variant { - if variant.kind == ty::VariantKind::Tuple && + if let Some((variant, did, substs)) = variant { + if variant.ctor_kind == CtorKind::Fn && !self.tcx.sess.features.borrow().relaxed_adts { emit_feature_err(&self.tcx.sess.parse_sess, - "relaxed_adts", span, GateIssue::Language, + "relaxed_adts", path.span, GateIssue::Language, "tuple structs and variants in struct patterns are unstable"); } - let ty = self.instantiate_type_path(def_id, path, node_id); + + // Check bounds on type arguments used in the path. + let type_predicates = self.tcx.lookup_predicates(did); + let bounds = self.instantiate_bounds(path.span, substs, &type_predicates); + let cause = traits::ObligationCause::new(path.span, self.body_id, + traits::ItemObligation(did)); + self.add_obligations_for_parameters(cause, &bounds); + Some((variant, ty)) } else { struct_span_err!(self.tcx.sess, path.span, E0071, - "`{}` does not name a struct or a struct variant", - pprust::path_to_string(path)) + "expected struct, variant or union type, found {}", + ty.sort_string(self.tcx)) .span_label(path.span, &format!("not a struct")) .emit(); None @@ -3280,12 +3293,11 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { base_expr: &'gcx Option>) -> Ty<'tcx> { // Find the relevant variant - let (variant, struct_ty) = if let Some(variant_ty) = self.check_struct_path(path, expr.id, - expr.span) { + let (variant, struct_ty) = if let Some(variant_ty) = self.check_struct_path(path, expr.id) { variant_ty } else { self.check_struct_fields_on_error(fields, base_expr); - return self.tcx().types.err; + return self.tcx.types.err; }; self.check_expr_struct_fields(struct_ty, path.span, variant, fields, @@ -3344,8 +3356,10 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { if ty.is_never() { if let Some(hir::map::NodeExpr(_)) = self.tcx.map.find(expr.id) { let adj_ty = self.next_diverging_ty_var(); - let adj = adjustment::AdjustNeverToAny(adj_ty); - self.write_adjustment(expr.id, adj); + self.write_adjustment(expr.id, adjustment::Adjustment { + kind: adjustment::Adjust::NeverToAny, + target: adj_ty + }); return adj_ty; } } @@ -3590,7 +3604,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { self.check_method_call(expr, name, &args[..], &tps[..], expected, lvalue_pref) } hir::ExprCast(ref e, ref t) => { - if let hir::TyFixedLengthVec(_, ref count_expr) = t.node { + if let hir::TyArray(_, ref count_expr) = t.node { self.check_expr_with_hint(&count_expr, tcx.types.usize); } @@ -3623,7 +3637,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { self.check_expr_eq_type(&e, typ); typ } - hir::ExprVec(ref args) => { + hir::ExprArray(ref args) => { let uty = expected.to_option(self).and_then(|uty| { match uty.sty { ty::TyArray(ty, _) | ty::TySlice(ty) => Some(ty), @@ -3701,9 +3715,8 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { _ => None } }); - let mut err_field = false; - let elt_ts = elts.iter().enumerate().map(|(i, e)| { + let elt_ts_iter = elts.iter().enumerate().map(|(i, e)| { let t = match flds { Some(ref fs) if i < fs.len() => { let ety = fs[i]; @@ -3714,13 +3727,13 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { self.check_expr_with_expectation(&e, NoExpectation) } }; - err_field = err_field || t.references_error(); t - }).collect(); - if err_field { + }); + let tuple = tcx.mk_tup(elt_ts_iter); + if tuple.references_error() { tcx.types.err } else { - tcx.mk_tup(elt_ts) + tuple } } hir::ExprStruct(ref path, ref fields, ref base_expr) => { @@ -3781,7 +3794,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { } } err.emit(); - self.tcx().types.err + self.tcx.types.err } } } @@ -3791,29 +3804,26 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { // Finish resolving a path in a struct expression or pattern `S::A { .. }` if necessary. // The newly resolved definition is written into `def_map`. - pub fn finish_resolving_struct_path(&self, - path: &hir::Path, - node_id: ast::NodeId, - span: Span) - -> Def + fn finish_resolving_struct_path(&self, + path: &hir::Path, + node_id: ast::NodeId) + -> (Def, Ty<'tcx>) { - let path_res = self.tcx().expect_resolution(node_id); - if path_res.depth == 0 { - // If fully resolved already, we don't have to do anything. - path_res.base_def - } else { - let base_ty_end = path.segments.len() - path_res.depth; - let (_ty, def) = AstConv::finish_resolving_def_to_ty(self, self, span, - PathParamMode::Optional, - path_res.base_def, - None, - node_id, - &path.segments[..base_ty_end], - &path.segments[base_ty_end..]); - // Write back the new resolution. - self.tcx().def_map.borrow_mut().insert(node_id, PathResolution::new(def)); - def + let path_res = self.tcx.expect_resolution(node_id); + let base_ty_end = path.segments.len() - path_res.depth; + let (ty, def) = AstConv::finish_resolving_def_to_ty(self, self, path.span, + PathParamMode::Optional, + path_res.base_def, + None, + node_id, + &path.segments[..base_ty_end], + &path.segments[base_ty_end..], + true); + // Write back the new resolution. + if path_res.depth != 0 { + self.tcx.def_map.borrow_mut().insert(node_id, PathResolution::new(def)); } + (def, ty) } // Resolve associated value path into a base type and associated constant or method definition. @@ -3825,7 +3835,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { span: Span) -> (Def, Option>, &'b [hir::PathSegment]) { - let path_res = self.tcx().expect_resolution(node_id); + let path_res = self.tcx.expect_resolution(node_id); if path_res.depth == 0 { // If fully resolved already, we don't have to do anything. (path_res.base_def, opt_self_ty, &path.segments) @@ -3839,7 +3849,8 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { opt_self_ty, node_id, &ty_segments[..base_ty_end], - &ty_segments[base_ty_end..]); + &ty_segments[base_ty_end..], + false); // Resolve an associated constant or method on the previously resolved type. let item_segment = path.segments.last().unwrap(); @@ -3859,7 +3870,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { }; // Write back the new resolution. - self.tcx().def_map.borrow_mut().insert(node_id, PathResolution::new(def)); + self.tcx.def_map.borrow_mut().insert(node_id, PathResolution::new(def)); (def, Some(ty), slice::ref_slice(item_segment)) } } @@ -4062,34 +4073,15 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { // // There are basically four cases to consider: // - // 1. Reference to a *type*, such as a struct or enum: - // - // mod a { struct Foo { ... } } - // - // Because we don't allow types to be declared within one - // another, a path that leads to a type will always look like - // `a::b::Foo` where `a` and `b` are modules. This implies - // that only the final segment can have type parameters, and - // they are located in the TypeSpace. - // - // *Note:* Generally speaking, references to types don't - // actually pass through this function, but rather the - // `ast_ty_to_ty` function in `astconv`. However, in the case - // of struct patterns (and maybe literals) we do invoke - // `instantiate_value_path` to get the general type of an instance of - // a struct. (In these cases, there are actually no type - // parameters permitted at present, but perhaps we will allow - // them in the future.) + // 1. Reference to a constructor of enum variant or struct: // - // 1b. Reference to an enum variant or tuple-like struct: - // - // struct foo(...) - // enum E { foo(...) } + // struct Foo(...) + // enum E { Foo(...) } // // In these cases, the parameters are declared in the type // space. // - // 2. Reference to a *fn item*: + // 2. Reference to a fn item or a free constant: // // fn foo() { } // @@ -4098,7 +4090,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { // type parameters. However, in this case, those parameters are // declared on a value, and hence are in the `FnSpace`. // - // 3. Reference to a *method*: + // 3. Reference to a method or an associated constant: // // impl SomeStruct { // fn foo(...) @@ -4110,15 +4102,9 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { // `SomeStruct::`, contains parameters in TypeSpace, and the // final segment, `foo::` contains parameters in fn space. // - // 4. Reference to an *associated const*: - // - // impl AnotherStruct { - // const FOO: B = BAR; - // } + // 4. Reference to a local variable // - // The path in this case will look like - // `a::b::AnotherStruct::::FOO`, so the penultimate segment - // only will have parameters in TypeSpace. + // Local variables can't have any type parameters. // // The first step then is to categorize the segments appropriately. @@ -4128,14 +4114,9 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { let mut type_segment = None; let mut fn_segment = None; match def { - // Case 1 and 1b. Reference to a *type* or *enum variant*. - Def::Struct(def_id) | - Def::Union(def_id) | - Def::Variant(def_id) | - Def::Enum(def_id) | - Def::TyAlias(def_id) | - Def::AssociatedTy(def_id) | - Def::Trait(def_id) => { + // Case 1. Reference to a struct/variant constructor. + Def::StructCtor(def_id, ..) | + Def::VariantCtor(def_id, ..) => { // Everything but the final segment should have no // parameters at all. let mut generics = self.tcx.lookup_generics(def_id); @@ -4178,17 +4159,10 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { fn_segment = Some((segments.last().unwrap(), generics)); } - // Other cases. Various nonsense that really shouldn't show up - // here. If they do, an error will have been reported - // elsewhere. (I hope) - Def::Mod(..) | - Def::PrimTy(..) | - Def::SelfTy(..) | - Def::TyParam(..) | - Def::Local(..) | - Def::Label(..) | - Def::Upvar(..) | - Def::Err => {} + // Case 4. Local variable, no generics. + Def::Local(..) | Def::Upvar(..) => {} + + _ => bug!("unexpected definition: {:?}", def), } // In `>::method`, `A` and `B` are mandatory, but @@ -4213,7 +4187,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { let ty = self.normalize_associated_types_in(span, &ty); self.write_ty(node_id, ty); self.write_substs(node_id, ty::ItemSubsts { - substs: Substs::empty(self.tcx) + substs: self.tcx.intern_substs(&[]) }); return ty; } @@ -4321,7 +4295,6 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { // the referenced item. let ty_substituted = self.instantiate_type_scheme(span, &substs, &scheme.ty); - if let Some((ty::ImplContainer(impl_def_id), self_ty)) = ufcs_associated { // In the case of `Foo::method` and `>::method`, if `method` // is inherent, there is no `Self` parameter, instead, the impl needs diff --git a/src/librustc_typeck/check/regionck.rs b/src/librustc_typeck/check/regionck.rs index 939deee27c..6f6538254c 100644 --- a/src/librustc_typeck/check/regionck.rs +++ b/src/librustc_typeck/check/regionck.rs @@ -259,23 +259,10 @@ impl<'a, 'gcx, 'tcx> RegionCtxt<'a, 'gcx, 'tcx> { self.resolve_type(t) } - fn resolve_method_type(&self, method_call: MethodCall) -> Option> { - let method_ty = self.tables.borrow().method_map - .get(&method_call).map(|method| method.ty); - method_ty.map(|method_ty| self.resolve_type(method_ty)) - } - /// Try to resolve the type for the given node. pub fn resolve_expr_type_adjusted(&mut self, expr: &hir::Expr) -> Ty<'tcx> { - let ty_unadjusted = self.resolve_node_type(expr.id); - if ty_unadjusted.references_error() { - ty_unadjusted - } else { - ty_unadjusted.adjust( - self.tcx, expr.span, expr.id, - self.tables.borrow().adjustments.get(&expr.id), - |method_call| self.resolve_method_type(method_call)) - } + let ty = self.tables.borrow().expr_ty_adjusted(expr); + self.resolve_type(ty) } fn visit_fn_body(&mut self, @@ -356,7 +343,7 @@ impl<'a, 'gcx, 'tcx> RegionCtxt<'a, 'gcx, 'tcx> { debug!("visit_region_obligations: r_o={:?} cause={:?}", r_o, r_o.cause); let sup_type = self.resolve_type(r_o.sup_type); - let origin = self.code_to_origin(r_o.cause.span, sup_type, &r_o.cause.code); + let origin = self.code_to_origin(&r_o.cause, sup_type); self.type_must_outlive(origin, sup_type, r_o.sub_region); } @@ -366,16 +353,11 @@ impl<'a, 'gcx, 'tcx> RegionCtxt<'a, 'gcx, 'tcx> { } fn code_to_origin(&self, - span: Span, - sup_type: Ty<'tcx>, - code: &traits::ObligationCauseCode<'tcx>) + cause: &traits::ObligationCause<'tcx>, + sup_type: Ty<'tcx>) -> SubregionOrigin<'tcx> { - match *code { - traits::ObligationCauseCode::ReferenceOutlivesReferent(ref_type) => - infer::ReferenceOutlivesReferent(ref_type, span), - _ => - infer::RelateParamBound(span, sup_type), - } + SubregionOrigin::from_obligation_cause(cause, + || infer::RelateParamBound(cause.span, sup_type)) } /// This method populates the region map's `free_region_map`. It walks over the transformed @@ -558,10 +540,8 @@ impl<'a, 'gcx, 'tcx, 'v> Visitor<'v> for RegionCtxt<'a, 'gcx, 'tcx> { let adjustment = self.tables.borrow().adjustments.get(&expr.id).map(|a| a.clone()); if let Some(adjustment) = adjustment { debug!("adjustment={:?}", adjustment); - match adjustment { - adjustment::AdjustDerefRef(adjustment::AutoDerefRef { - autoderefs, ref autoref, .. - }) => { + match adjustment.kind { + adjustment::Adjust::DerefRef { autoderefs, ref autoref, .. } => { let expr_ty = self.resolve_node_type(expr.id); self.constrain_autoderefs(expr, autoderefs, expr_ty); if let Some(ref autoref) = *autoref { @@ -951,7 +931,7 @@ impl<'a, 'gcx, 'tcx> RegionCtxt<'a, 'gcx, 'tcx> { let origin = infer::ParameterOrigin::OverloadedDeref; self.substs_wf_in_scope(origin, method.substs, deref_expr.span, r_deref_expr); - // Treat overloaded autoderefs as if an AutoRef adjustment + // Treat overloaded autoderefs as if an AutoBorrow adjustment // was applied on the base type, as that is always the case. let fn_sig = method.ty.fn_sig(); let fn_sig = // late-bound regions should have been instantiated @@ -1065,15 +1045,12 @@ impl<'a, 'gcx, 'tcx> RegionCtxt<'a, 'gcx, 'tcx> { id: ast::NodeId, minimum_lifetime: &'tcx ty::Region) { - let tcx = self.tcx; - // Try to resolve the type. If we encounter an error, then typeck // is going to fail anyway, so just stop here and let typeck // report errors later on in the writeback phase. let ty0 = self.resolve_node_type(id); - let ty = ty0.adjust(tcx, origin.span(), id, - self.tables.borrow().adjustments.get(&id), - |method_call| self.resolve_method_type(method_call)); + let ty = self.tables.borrow().adjustments.get(&id).map_or(ty0, |adj| adj.target); + let ty = self.resolve_type(ty); debug!("constrain_regions_in_type_of_node(\ ty={}, ty0={}, id={}, minimum_lifetime={:?})", ty, ty0, @@ -1170,7 +1147,7 @@ impl<'a, 'gcx, 'tcx> RegionCtxt<'a, 'gcx, 'tcx> { fn link_autoref(&self, expr: &hir::Expr, autoderefs: usize, - autoref: &adjustment::AutoRef<'tcx>) + autoref: &adjustment::AutoBorrow<'tcx>) { debug!("link_autoref(autoref={:?})", autoref); let mc = mc::MemCategorizationContext::new(self); @@ -1178,12 +1155,12 @@ impl<'a, 'gcx, 'tcx> RegionCtxt<'a, 'gcx, 'tcx> { debug!("expr_cmt={:?}", expr_cmt); match *autoref { - adjustment::AutoPtr(r, m) => { + adjustment::AutoBorrow::Ref(r, m) => { self.link_region(expr.span, r, ty::BorrowKind::from_mutbl(m), expr_cmt); } - adjustment::AutoUnsafe(m) => { + adjustment::AutoBorrow::RawPtr(m) => { let r = self.tcx.node_scope_region(expr.id); self.link_region(expr.span, r, ty::BorrowKind::from_mutbl(m), expr_cmt); } @@ -1474,7 +1451,7 @@ impl<'a, 'gcx, 'tcx> RegionCtxt<'a, 'gcx, 'tcx> { assert!(!ty.has_escaping_regions()); - let components = self.outlives_components(ty); + let components = self.tcx.outlives_components(ty); self.components_must_outlive(origin, components, region); } diff --git a/src/librustc_typeck/check/wfcheck.rs b/src/librustc_typeck/check/wfcheck.rs index bc5cb68995..be1f2e3567 100644 --- a/src/librustc_typeck/check/wfcheck.rs +++ b/src/librustc_typeck/check/wfcheck.rs @@ -150,7 +150,7 @@ impl<'ccx, 'gcx> CheckTypeWellFormedVisitor<'ccx, 'gcx> { self.check_variances_for_type_defn(item, ast_generics); } hir::ItemEnum(ref enum_def, ref ast_generics) => { - self.check_type_defn(item, false, |fcx| { + self.check_type_defn(item, true, |fcx| { fcx.enum_variants(enum_def) }); @@ -416,7 +416,7 @@ impl<'ccx, 'gcx> CheckTypeWellFormedVisitor<'ccx, 'gcx> { } } None => { - let self_ty = fcx.tcx.node_id_to_type(item.id); + let self_ty = fcx.tcx.tables().node_id_to_type(item.id); let self_ty = fcx.instantiate_type_scheme(item.span, free_substs, &self_ty); fcx.register_wf_obligation(self_ty, ast_self_ty.span, this.code.clone()); } @@ -519,7 +519,7 @@ impl<'ccx, 'gcx> CheckTypeWellFormedVisitor<'ccx, 'gcx> { item: &hir::Item, ast_generics: &hir::Generics) { - let ty = self.tcx().node_id_to_type(item.id); + let ty = self.tcx().tables().node_id_to_type(item.id); if self.tcx().has_error_field(ty) { return; } @@ -649,7 +649,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { let fields = struct_def.fields().iter() .map(|field| { - let field_ty = self.tcx.node_id_to_type(field.id); + let field_ty = self.tcx.tables().node_id_to_type(field.id); let field_ty = self.instantiate_type_scheme(field.span, &self.parameter_environment .free_substs, diff --git a/src/librustc_typeck/check/writeback.rs b/src/librustc_typeck/check/writeback.rs index 0b70d904c2..5ef3e86996 100644 --- a/src/librustc_typeck/check/writeback.rs +++ b/src/librustc_typeck/check/writeback.rs @@ -229,7 +229,7 @@ impl<'cx, 'gcx, 'tcx, 'v> Visitor<'v> for WritebackCx<'cx, 'gcx, 'tcx> { debug!("Type for pattern binding {} (id {}) resolved to {:?}", pat_to_string(p), p.id, - self.tcx().node_id_to_type(p.id)); + self.tcx().tables().node_id_to_type(p.id)); intravisit::walk_pat(self, p); } @@ -247,7 +247,7 @@ impl<'cx, 'gcx, 'tcx, 'v> Visitor<'v> for WritebackCx<'cx, 'gcx, 'tcx> { fn visit_ty(&mut self, t: &hir::Ty) { match t.node { - hir::TyFixedLengthVec(ref ty, ref count_expr) => { + hir::TyArray(ref ty, ref count_expr) => { self.visit_ty(&ty); write_ty_to_tcx(self.fcx.ccx, count_expr.id, self.tcx().types.usize); } @@ -381,36 +381,40 @@ impl<'cx, 'gcx, 'tcx> WritebackCx<'cx, 'gcx, 'tcx> { } Some(adjustment) => { - let resolved_adjustment = match adjustment { - adjustment::AdjustNeverToAny(ty) => { - adjustment::AdjustNeverToAny(self.resolve(&ty, reason)) + let resolved_adjustment = match adjustment.kind { + adjustment::Adjust::NeverToAny => { + adjustment::Adjust::NeverToAny } - adjustment::AdjustReifyFnPointer => { - adjustment::AdjustReifyFnPointer + adjustment::Adjust::ReifyFnPointer => { + adjustment::Adjust::ReifyFnPointer } - adjustment::AdjustMutToConstPointer => { - adjustment::AdjustMutToConstPointer + adjustment::Adjust::MutToConstPointer => { + adjustment::Adjust::MutToConstPointer } - adjustment::AdjustUnsafeFnPointer => { - adjustment::AdjustUnsafeFnPointer + adjustment::Adjust::UnsafeFnPointer => { + adjustment::Adjust::UnsafeFnPointer } - adjustment::AdjustDerefRef(adj) => { - for autoderef in 0..adj.autoderefs { + adjustment::Adjust::DerefRef { autoderefs, autoref, unsize } => { + for autoderef in 0..autoderefs { let method_call = MethodCall::autoderef(id, autoderef as u32); self.visit_method_map_entry(reason, method_call); } - adjustment::AdjustDerefRef(adjustment::AutoDerefRef { - autoderefs: adj.autoderefs, - autoref: self.resolve(&adj.autoref, reason), - unsize: self.resolve(&adj.unsize, reason), - }) + adjustment::Adjust::DerefRef { + autoderefs: autoderefs, + autoref: self.resolve(&autoref, reason), + unsize: unsize, + } } }; + let resolved_adjustment = adjustment::Adjustment { + kind: resolved_adjustment, + target: self.resolve(&adjustment.target, reason) + }; debug!("Adjustments for node {}: {:?}", id, resolved_adjustment); self.tcx().tables.borrow_mut().adjustments.insert( id, resolved_adjustment); diff --git a/src/librustc_typeck/check_unused.rs b/src/librustc_typeck/check_unused.rs index f66f15b238..7e41a672bf 100644 --- a/src/librustc_typeck/check_unused.rs +++ b/src/librustc_typeck/check_unused.rs @@ -30,10 +30,13 @@ impl<'a, 'tcx> UnusedTraitImportVisitor<'a, 'tcx> { if self.tcx.used_trait_imports.borrow().contains(&id) { return; } - self.tcx.sess.add_lint(lint::builtin::UNUSED_IMPORTS, - id, - span, - "unused import".to_string()); + + let msg = if let Ok(snippet) = self.tcx.sess.codemap().span_to_snippet(span) { + format!("unused import: `{}`", snippet) + } else { + "unused import".to_string() + }; + self.tcx.sess.add_lint(lint::builtin::UNUSED_IMPORTS, id, span, msg); } } diff --git a/src/librustc_typeck/coherence/mod.rs b/src/librustc_typeck/coherence/mod.rs index 3b4c98fc71..4a4dea5b51 100644 --- a/src/librustc_typeck/coherence/mod.rs +++ b/src/librustc_typeck/coherence/mod.rs @@ -20,7 +20,7 @@ use middle::lang_items::UnsizeTraitLangItem; use rustc::ty::subst::Subst; use rustc::ty::{self, TyCtxt, TypeFoldable}; use rustc::traits::{self, Reveal}; -use rustc::ty::{ParameterEnvironment}; +use rustc::ty::ParameterEnvironment; use rustc::ty::{Ty, TyBool, TyChar, TyError}; use rustc::ty::{TyParam, TyRawPtr}; use rustc::ty::{TyRef, TyAdt, TyTrait, TyNever, TyTuple}; @@ -44,13 +44,13 @@ mod orphan; mod overlap; mod unsafety; -struct CoherenceChecker<'a, 'gcx: 'a+'tcx, 'tcx: 'a> { +struct CoherenceChecker<'a, 'gcx: 'a + 'tcx, 'tcx: 'a> { crate_context: &'a CrateCtxt<'a, 'gcx>, inference_context: InferCtxt<'a, 'gcx, 'tcx>, } -struct CoherenceCheckVisitor<'a, 'gcx: 'a+'tcx, 'tcx: 'a> { - cc: &'a CoherenceChecker<'a, 'gcx, 'tcx> +struct CoherenceCheckVisitor<'a, 'gcx: 'a + 'tcx, 'tcx: 'a> { + cc: &'a CoherenceChecker<'a, 'gcx, 'tcx>, } impl<'a, 'gcx, 'tcx, 'v> intravisit::Visitor<'v> for CoherenceCheckVisitor<'a, 'gcx, 'tcx> { @@ -62,36 +62,25 @@ impl<'a, 'gcx, 'tcx, 'v> intravisit::Visitor<'v> for CoherenceCheckVisitor<'a, ' } impl<'a, 'gcx, 'tcx> CoherenceChecker<'a, 'gcx, 'tcx> { - // Returns the def ID of the base type, if there is one. fn get_base_type_def_id(&self, span: Span, ty: Ty<'tcx>) -> Option { match ty.sty { - TyAdt(def, _) => { - Some(def.did) - } + TyAdt(def, _) => Some(def.did), - TyTrait(ref t) => { - Some(t.principal.def_id()) - } + TyTrait(ref t) => Some(t.principal.def_id()), - TyBox(_) => { - self.inference_context.tcx.lang_items.owned_box() - } + TyBox(_) => self.inference_context.tcx.lang_items.owned_box(), - TyBool | TyChar | TyInt(..) | TyUint(..) | TyFloat(..) | - TyStr | TyArray(..) | TySlice(..) | TyFnDef(..) | TyFnPtr(_) | - TyTuple(..) | TyParam(..) | TyError | TyNever | - TyRawPtr(_) | TyRef(..) | TyProjection(..) => { - None - } + TyBool | TyChar | TyInt(..) | TyUint(..) | TyFloat(..) | TyStr | TyArray(..) | + TySlice(..) | TyFnDef(..) | TyFnPtr(_) | TyTuple(..) | TyParam(..) | TyError | + TyNever | TyRawPtr(_) | TyRef(..) | TyProjection(..) => None, TyInfer(..) | TyClosure(..) | TyAnon(..) => { // `ty` comes from a user declaration so we should only expect types // that the user can type - span_bug!( - span, - "coherence encountered unexpected type searching for base type: {}", - ty); + span_bug!(span, + "coherence encountered unexpected type searching for base type: {}", + ty); } } } @@ -100,9 +89,8 @@ impl<'a, 'gcx, 'tcx> CoherenceChecker<'a, 'gcx, 'tcx> { // Check implementations and traits. This populates the tables // containing the inherent methods and extension methods. It also // builds up the trait inheritance table. - self.crate_context.tcx.visit_all_items_in_krate( - DepNode::CoherenceCheckImpl, - &mut CoherenceCheckVisitor { cc: self }); + self.crate_context.tcx.visit_all_items_in_krate(DepNode::CoherenceCheckImpl, + &mut CoherenceCheckVisitor { cc: self }); // Populate the table of destructors. It might seem a bit strange to // do this here, but it's actually the most convenient place, since @@ -167,7 +155,8 @@ impl<'a, 'gcx, 'tcx> CoherenceChecker<'a, 'gcx, 'tcx> { fn add_trait_impl(&self, impl_trait_ref: ty::TraitRef<'gcx>, impl_def_id: DefId) { debug!("add_trait_impl: impl_trait_ref={:?} impl_def_id={:?}", - impl_trait_ref, impl_def_id); + impl_trait_ref, + impl_def_id); let trait_def = self.crate_context.tcx.lookup_trait_def(impl_trait_ref.def_id); trait_def.record_local_impl(self.crate_context.tcx, impl_def_id, impl_trait_ref); } @@ -176,9 +165,9 @@ impl<'a, 'gcx, 'tcx> CoherenceChecker<'a, 'gcx, 'tcx> { fn create_impl_from_item(&self, item: &Item) -> Vec { match item.node { ItemImpl(.., ref impl_items) => { - impl_items.iter().map(|impl_item| { - self.crate_context.tcx.map.local_def_id(impl_item.id) - }).collect() + impl_items.iter() + .map(|impl_item| self.crate_context.tcx.map.local_def_id(impl_item.id)) + .collect() } _ => { span_bug!(item.span, "can't convert a non-impl to an impl"); @@ -186,14 +175,14 @@ impl<'a, 'gcx, 'tcx> CoherenceChecker<'a, 'gcx, 'tcx> { } } - // // Destructors // fn populate_destructors(&self) { let tcx = self.crate_context.tcx; let drop_trait = match tcx.lang_items.drop_trait() { - Some(id) => id, None => { return } + Some(id) => id, + None => return, }; tcx.populate_implementations_for_trait_if_necessary(drop_trait); let drop_trait = tcx.lookup_trait_def(drop_trait); @@ -219,13 +208,14 @@ impl<'a, 'gcx, 'tcx> CoherenceChecker<'a, 'gcx, 'tcx> { match tcx.map.find(impl_node_id) { Some(hir_map::NodeItem(item)) => { let span = match item.node { - ItemImpl(.., ref ty, _) => { - ty.span - }, - _ => item.span + ItemImpl(.., ref ty, _) => ty.span, + _ => item.span, }; - struct_span_err!(tcx.sess, span, E0120, - "the Drop trait may only be implemented on structures") + struct_span_err!(tcx.sess, + span, + E0120, + "the Drop trait may only be implemented on \ + structures") .span_label(span, &format!("implementing Drop requires a struct")) .emit(); @@ -254,15 +244,14 @@ impl<'a, 'gcx, 'tcx> CoherenceChecker<'a, 'gcx, 'tcx> { let copy_trait = tcx.lookup_trait_def(copy_trait); copy_trait.for_each_impl(tcx, |impl_did| { - debug!("check_implementations_of_copy: impl_did={:?}", - impl_did); + debug!("check_implementations_of_copy: impl_did={:?}", impl_did); let impl_node_id = if let Some(n) = tcx.map.as_local_node_id(impl_did) { n } else { debug!("check_implementations_of_copy(): impl not in this \ crate"); - return + return; }; let self_type = tcx.lookup_item_type(impl_did); @@ -280,14 +269,12 @@ impl<'a, 'gcx, 'tcx> CoherenceChecker<'a, 'gcx, 'tcx> { match param_env.can_type_implement_copy(tcx, self_type, span) { Ok(()) => {} Err(CopyImplementationError::InfrigingField(name)) => { - struct_span_err!(tcx.sess, span, E0204, - "the trait `Copy` may not be implemented for \ - this type") - .span_label(span, &format!( - "field `{}` does not implement `Copy`", name) - ) - .emit() - + struct_span_err!(tcx.sess, + span, + E0204, + "the trait `Copy` may not be implemented for this type") + .span_label(span, &format!("field `{}` does not implement `Copy`", name)) + .emit() } Err(CopyImplementationError::InfrigingVariant(name)) => { let item = tcx.map.expect_item(impl_node_id); @@ -297,10 +284,12 @@ impl<'a, 'gcx, 'tcx> CoherenceChecker<'a, 'gcx, 'tcx> { span }; - struct_span_err!(tcx.sess, span, E0205, + struct_span_err!(tcx.sess, + span, + E0205, "the trait `Copy` may not be implemented for this type") - .span_label(span, &format!("variant `{}` does not implement `Copy`", - name)) + .span_label(span, + &format!("variant `{}` does not implement `Copy`", name)) .emit() } Err(CopyImplementationError::NotAnAdt) => { @@ -311,15 +300,19 @@ impl<'a, 'gcx, 'tcx> CoherenceChecker<'a, 'gcx, 'tcx> { span }; - struct_span_err!(tcx.sess, span, E0206, + struct_span_err!(tcx.sess, + span, + E0206, "the trait `Copy` may not be implemented for this type") .span_label(span, &format!("type is not a structure or enumeration")) .emit(); } Err(CopyImplementationError::HasDestructor) => { - struct_span_err!(tcx.sess, span, E0184, - "the trait `Copy` may not be implemented for this type; \ - the type has a destructor") + struct_span_err!(tcx.sess, + span, + E0184, + "the trait `Copy` may not be implemented for this type; the \ + type has a destructor") .span_label(span, &format!("Copy not allowed on types with destructors")) .emit(); } @@ -359,7 +352,8 @@ impl<'a, 'gcx, 'tcx> CoherenceChecker<'a, 'gcx, 'tcx> { let trait_ref = self.crate_context.tcx.impl_trait_ref(impl_did).unwrap(); let target = trait_ref.substs.type_at(1); debug!("check_implementations_of_coerce_unsized: {:?} -> {:?} (bound)", - source, target); + source, + target); let span = tcx.map.span(impl_node_id); let param_env = ParameterEnvironment::for_item(tcx, impl_node_id); @@ -368,15 +362,19 @@ impl<'a, 'gcx, 'tcx> CoherenceChecker<'a, 'gcx, 'tcx> { assert!(!source.has_escaping_regions()); debug!("check_implementations_of_coerce_unsized: {:?} -> {:?} (free)", - source, target); + source, + target); tcx.infer_ctxt(None, Some(param_env), Reveal::ExactMatch).enter(|infcx| { let origin = TypeOrigin::Misc(span); - let check_mutbl = |mt_a: ty::TypeAndMut<'gcx>, mt_b: ty::TypeAndMut<'gcx>, + let check_mutbl = |mt_a: ty::TypeAndMut<'gcx>, + mt_b: ty::TypeAndMut<'gcx>, mk_ptr: &Fn(Ty<'gcx>) -> Ty<'gcx>| { if (mt_a.mutbl, mt_b.mutbl) == (hir::MutImmutable, hir::MutMutable) { - infcx.report_mismatched_types(origin, mk_ptr(mt_b.ty), - target, ty::error::TypeError::Mutability); + infcx.report_mismatched_types(origin, + mk_ptr(mt_b.ty), + target, + ty::error::TypeError::Mutability); } (mt_a.ty, mt_b.ty, unsize_trait, None) }; @@ -394,37 +392,49 @@ impl<'a, 'gcx, 'tcx> CoherenceChecker<'a, 'gcx, 'tcx> { } (&ty::TyAdt(def_a, substs_a), &ty::TyAdt(def_b, substs_b)) - if def_a.is_struct() && def_b.is_struct() => { + if def_a.is_struct() && def_b.is_struct() => { if def_a != def_b { let source_path = tcx.item_path_str(def_a.did); let target_path = tcx.item_path_str(def_b.did); - span_err!(tcx.sess, span, E0377, + span_err!(tcx.sess, + span, + E0377, "the trait `CoerceUnsized` may only be implemented \ for a coercion between structures with the same \ definition; expected {}, found {}", - source_path, target_path); + source_path, + target_path); return; } let fields = &def_a.struct_variant().fields; - let diff_fields = fields.iter().enumerate().filter_map(|(i, f)| { - let (a, b) = (f.ty(tcx, substs_a), f.ty(tcx, substs_b)); + let diff_fields = fields.iter() + .enumerate() + .filter_map(|(i, f)| { + let (a, b) = (f.ty(tcx, substs_a), f.ty(tcx, substs_b)); + + if f.unsubst_ty().is_phantom_data() { + // Ignore PhantomData fields + return None; + } - if f.unsubst_ty().is_phantom_data() { - // Ignore PhantomData fields - None - } else if infcx.sub_types(false, origin, b, a).is_ok() { // Ignore fields that aren't significantly changed - None - } else { + if let Ok(ok) = infcx.sub_types(false, origin, b, a) { + if ok.obligations.is_empty() { + return None; + } + } + // Collect up all fields that were significantly changed // i.e. those that contain T in coerce_unsized T -> U Some((i, a, b)) - } - }).collect::>(); + }) + .collect::>(); if diff_fields.is_empty() { - span_err!(tcx.sess, span, E0374, + span_err!(tcx.sess, + span, + E0374, "the trait `CoerceUnsized` may only be implemented \ for a coercion between structures with one field \ being coerced, none found"); @@ -437,16 +447,22 @@ impl<'a, 'gcx, 'tcx> CoherenceChecker<'a, 'gcx, 'tcx> { tcx.map.span(impl_node_id) }; - let mut err = struct_span_err!(tcx.sess, span, E0375, - "implementing the trait `CoerceUnsized` \ - requires multiple coercions"); + let mut err = struct_span_err!(tcx.sess, + span, + E0375, + "implementing the trait \ + `CoerceUnsized` requires multiple \ + coercions"); err.note("`CoerceUnsized` may only be implemented for \ a coercion between structures with one field being coerced"); err.note(&format!("currently, {} fields need coercions: {}", - diff_fields.len(), - diff_fields.iter().map(|&(i, a, b)| { - format!("{} ({} to {})", fields[i].name, a, b) - }).collect::>().join(", ") )); + diff_fields.len(), + diff_fields.iter() + .map(|&(i, a, b)| { + format!("{} ({} to {})", fields[i].name, a, b) + }) + .collect::>() + .join(", "))); err.span_label(span, &format!("requires multiple coercions")); err.emit(); return; @@ -458,7 +474,9 @@ impl<'a, 'gcx, 'tcx> CoherenceChecker<'a, 'gcx, 'tcx> { } _ => { - span_err!(tcx.sess, span, E0376, + span_err!(tcx.sess, + span, + E0376, "the trait `CoerceUnsized` may only be implemented \ for a coercion between structures"); return; @@ -469,8 +487,8 @@ impl<'a, 'gcx, 'tcx> CoherenceChecker<'a, 'gcx, 'tcx> { // Register an obligation for `A: Trait`. let cause = traits::ObligationCause::misc(span, impl_node_id); - let predicate = tcx.predicate_for_trait_def(cause, trait_def_id, 0, - source, &[target]); + let predicate = + tcx.predicate_for_trait_def(cause, trait_def_id, 0, source, &[target]); fulfill_cx.register_predicate_obligation(&infcx, predicate); // Check that all transitive obligations are satisfied. @@ -480,8 +498,8 @@ impl<'a, 'gcx, 'tcx> CoherenceChecker<'a, 'gcx, 'tcx> { // Finally, resolve all regions. let mut free_regions = FreeRegionMap::new(); - free_regions.relate_free_regions_from_predicates( - &infcx.parameter_environment.caller_bounds); + free_regions.relate_free_regions_from_predicates(&infcx.parameter_environment + .caller_bounds); infcx.resolve_regions_and_report_errors(&free_regions, impl_node_id); if let Some(kind) = kind { @@ -495,7 +513,7 @@ impl<'a, 'gcx, 'tcx> CoherenceChecker<'a, 'gcx, 'tcx> { fn enforce_trait_manually_implementable(tcx: TyCtxt, sp: Span, trait_def_id: DefId) { if tcx.sess.features.borrow().unboxed_closures { // the feature gate allows all of them - return + return; } let did = Some(trait_def_id); let li = &tcx.lang_items; @@ -507,14 +525,15 @@ fn enforce_trait_manually_implementable(tcx: TyCtxt, sp: Span, trait_def_id: Def } else if did == li.fn_once_trait() { "FnOnce" } else { - return // everything OK + return; // everything OK }; let mut err = struct_span_err!(tcx.sess, sp, E0183, "manual implementations of `{}` are experimental", trait_name); - help!(&mut err, "add `#![feature(unboxed_closures)]` to the crate attributes to enable"); + help!(&mut err, + "add `#![feature(unboxed_closures)]` to the crate attributes to enable"); err.emit(); } @@ -522,9 +541,10 @@ pub fn check_coherence(ccx: &CrateCtxt) { let _task = ccx.tcx.dep_graph.in_task(DepNode::Coherence); ccx.tcx.infer_ctxt(None, None, Reveal::ExactMatch).enter(|infcx| { CoherenceChecker { - crate_context: ccx, - inference_context: infcx, - }.check(); + crate_context: ccx, + inference_context: infcx, + } + .check(); }); unsafety::check(ccx.tcx); orphan::check(ccx.tcx); diff --git a/src/librustc_typeck/coherence/orphan.rs b/src/librustc_typeck/coherence/orphan.rs index 70342a0cd2..bff794364c 100644 --- a/src/librustc_typeck/coherence/orphan.rs +++ b/src/librustc_typeck/coherence/orphan.rs @@ -25,17 +25,20 @@ pub fn check<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>) { tcx.visit_all_items_in_krate(DepNode::CoherenceOrphanCheck, &mut orphan); } -struct OrphanChecker<'cx, 'tcx:'cx> { - tcx: TyCtxt<'cx, 'tcx, 'tcx> +struct OrphanChecker<'cx, 'tcx: 'cx> { + tcx: TyCtxt<'cx, 'tcx, 'tcx>, } impl<'cx, 'tcx> OrphanChecker<'cx, 'tcx> { fn check_def_id(&self, item: &hir::Item, def_id: DefId) { if def_id.krate != LOCAL_CRATE { - struct_span_err!(self.tcx.sess, item.span, E0116, - "cannot define inherent `impl` for a type outside of the \ - crate where the type is defined") - .span_label(item.span, &format!("impl for type defined outside of crate.")) + struct_span_err!(self.tcx.sess, + item.span, + E0116, + "cannot define inherent `impl` for a type outside of the crate \ + where the type is defined") + .span_label(item.span, + &format!("impl for type defined outside of crate.")) .note("define and implement a trait or new type instead") .emit(); } @@ -48,11 +51,17 @@ impl<'cx, 'tcx> OrphanChecker<'cx, 'tcx> { ty: &str, span: Span) { match lang_def_id { - Some(lang_def_id) if lang_def_id == impl_def_id => { /* OK */ }, + Some(lang_def_id) if lang_def_id == impl_def_id => { + // OK + } _ => { - struct_span_err!(self.tcx.sess, span, E0390, - "only a single inherent implementation marked with `#[lang = \"{}\"]` \ - is allowed for the `{}` primitive", lang, ty) + struct_span_err!(self.tcx.sess, + span, + E0390, + "only a single inherent implementation marked with `#[lang = \ + \"{}\"]` is allowed for the `{}` primitive", + lang, + ty) .span_help(span, "consider using a trait to implement these methods") .emit(); } @@ -209,12 +218,14 @@ impl<'cx, 'tcx> OrphanChecker<'cx, 'tcx> { return; } _ => { - struct_span_err!(self.tcx.sess, ty.span, E0118, + struct_span_err!(self.tcx.sess, + ty.span, + E0118, "no base type found for inherent implementation") - .span_label(ty.span, &format!("impl requires a base type")) - .note(&format!("either implement a trait on it or create a newtype \ - to wrap it instead")) - .emit(); + .span_label(ty.span, &format!("impl requires a base type")) + .note(&format!("either implement a trait on it or create a newtype \ + to wrap it instead")) + .emit(); return; } } @@ -226,20 +237,23 @@ impl<'cx, 'tcx> OrphanChecker<'cx, 'tcx> { let trait_ref = self.tcx.impl_trait_ref(def_id).unwrap(); let trait_def_id = trait_ref.def_id; match traits::orphan_check(self.tcx, def_id) { - Ok(()) => { } + Ok(()) => {} Err(traits::OrphanCheckErr::NoLocalInputType) => { - struct_span_err!( - self.tcx.sess, item.span, E0117, - "only traits defined in the current crate can be \ - implemented for arbitrary types") - .span_label(item.span, &format!("impl doesn't use types inside crate")) - .note(&format!("the impl does not reference any \ - types defined in this crate")) - .emit(); + struct_span_err!(self.tcx.sess, + item.span, + E0117, + "only traits defined in the current crate can be \ + implemented for arbitrary types") + .span_label(item.span, &format!("impl doesn't use types inside crate")) + .note(&format!("the impl does not reference any types defined in \ + this crate")) + .emit(); return; } Err(traits::OrphanCheckErr::UncoveredTy(param_ty)) => { - span_err!(self.tcx.sess, item.span, E0210, + span_err!(self.tcx.sess, + item.span, + E0210, "type parameter `{}` must be used as the type parameter for \ some local type (e.g. `MyStruct`); only traits defined in \ the current crate can be implemented for a type parameter", @@ -285,10 +299,8 @@ impl<'cx, 'tcx> OrphanChecker<'cx, 'tcx> { trait_ref, trait_def_id, self.tcx.trait_has_default_impl(trait_def_id)); - if - self.tcx.trait_has_default_impl(trait_def_id) && - trait_def_id.krate != LOCAL_CRATE - { + if self.tcx.trait_has_default_impl(trait_def_id) && + trait_def_id.krate != LOCAL_CRATE { let self_ty = trait_ref.self_ty(); let opt_self_def_id = match self_ty.sty { ty::TyAdt(self_def, _) => Some(self_def.did), @@ -305,20 +317,17 @@ impl<'cx, 'tcx> OrphanChecker<'cx, 'tcx> { if self_def_id.is_local() { None } else { - Some(format!( - "cross-crate traits with a default impl, like `{}`, \ - can only be implemented for a struct/enum type \ - defined in the current crate", - self.tcx.item_path_str(trait_def_id))) + Some(format!("cross-crate traits with a default impl, like `{}`, \ + can only be implemented for a struct/enum type \ + defined in the current crate", + self.tcx.item_path_str(trait_def_id))) } } _ => { - Some(format!( - "cross-crate traits with a default impl, like `{}`, \ - can only be implemented for a struct/enum type, \ - not `{}`", - self.tcx.item_path_str(trait_def_id), - self_ty)) + Some(format!("cross-crate traits with a default impl, like `{}`, can \ + only be implemented for a struct/enum type, not `{}`", + self.tcx.item_path_str(trait_def_id), + self_ty)) } }; @@ -330,14 +339,18 @@ impl<'cx, 'tcx> OrphanChecker<'cx, 'tcx> { // Disallow *all* explicit impls of `Sized` and `Unsize` for now. if Some(trait_def_id) == self.tcx.lang_items.sized_trait() { - struct_span_err!(self.tcx.sess, item.span, E0322, - "explicit impls for the `Sized` trait are not permitted") + struct_span_err!(self.tcx.sess, + item.span, + E0322, + "explicit impls for the `Sized` trait are not permitted") .span_label(item.span, &format!("impl of 'Sized' not allowed")) .emit(); return; } if Some(trait_def_id) == self.tcx.lang_items.unsize_trait() { - span_err!(self.tcx.sess, item.span, E0328, + span_err!(self.tcx.sess, + item.span, + E0328, "explicit impls for the `Unsize` trait are not permitted"); return; } @@ -348,9 +361,11 @@ impl<'cx, 'tcx> OrphanChecker<'cx, 'tcx> { self.tcx.map.node_to_string(item.id)); let trait_ref = self.tcx.impl_trait_ref(def_id).unwrap(); if trait_ref.def_id.krate != LOCAL_CRATE { - struct_span_err!(self.tcx.sess, item_trait_ref.path.span, E0318, - "cannot create default implementations for traits outside the \ - crate they're defined in; define a new trait instead") + struct_span_err!(self.tcx.sess, + item_trait_ref.path.span, + E0318, + "cannot create default implementations for traits outside \ + the crate they're defined in; define a new trait instead") .span_label(item_trait_ref.path.span, &format!("`{}` trait not defined in this crate", item_trait_ref.path)) @@ -365,7 +380,7 @@ impl<'cx, 'tcx> OrphanChecker<'cx, 'tcx> { } } -impl<'cx, 'tcx,'v> intravisit::Visitor<'v> for OrphanChecker<'cx, 'tcx> { +impl<'cx, 'tcx, 'v> intravisit::Visitor<'v> for OrphanChecker<'cx, 'tcx> { fn visit_item(&mut self, item: &hir::Item) { self.check_item(item); } diff --git a/src/librustc_typeck/coherence/overlap.rs b/src/librustc_typeck/coherence/overlap.rs index c42b8f8840..1bf140c21a 100644 --- a/src/librustc_typeck/coherence/overlap.rs +++ b/src/librustc_typeck/coherence/overlap.rs @@ -23,15 +23,17 @@ use util::nodemap::DefIdMap; use lint; pub fn check<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>) { - let mut overlap = OverlapChecker { tcx: tcx, - default_impls: DefIdMap() }; + let mut overlap = OverlapChecker { + tcx: tcx, + default_impls: DefIdMap(), + }; // this secondary walk specifically checks for some other cases, // like defaulted traits, for which additional overlap rules exist tcx.visit_all_items_in_krate(DepNode::CoherenceOverlapCheckSpecial, &mut overlap); } -struct OverlapChecker<'cx, 'tcx:'cx> { +struct OverlapChecker<'cx, 'tcx: 'cx> { tcx: TyCtxt<'cx, 'tcx, 'tcx>, // maps from a trait def-id to an impl id @@ -41,18 +43,21 @@ struct OverlapChecker<'cx, 'tcx:'cx> { impl<'cx, 'tcx> OverlapChecker<'cx, 'tcx> { fn check_for_common_items_in_impls(&self, impl1: DefId, impl2: DefId) { #[derive(Copy, Clone, PartialEq)] - enum Namespace { Type, Value } + enum Namespace { + Type, + Value, + } fn name_and_namespace<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, def_id: DefId) - -> (ast::Name, Namespace) - { + -> (ast::Name, Namespace) { let item = tcx.impl_or_trait_item(def_id); - (item.name(), match item { - ty::TypeTraitItem(..) => Namespace::Type, - ty::ConstTraitItem(..) => Namespace::Value, - ty::MethodTraitItem(..) => Namespace::Value, - }) + (item.name(), + match item { + ty::TypeTraitItem(..) => Namespace::Type, + ty::ConstTraitItem(..) => Namespace::Value, + ty::MethodTraitItem(..) => Namespace::Value, + }) } let impl_items = self.tcx.impl_or_trait_item_def_ids.borrow(); @@ -79,11 +84,11 @@ impl<'cx, 'tcx> OverlapChecker<'cx, 'tcx> { let inherent_impls = self.tcx.inherent_impls.borrow(); let impls = match inherent_impls.get(&ty_def_id) { Some(impls) => impls, - None => return + None => return, }; for (i, &impl1_def_id) in impls.iter().enumerate() { - for &impl2_def_id in &impls[(i+1)..] { + for &impl2_def_id in &impls[(i + 1)..] { self.tcx.infer_ctxt(None, None, Reveal::ExactMatch).enter(|infcx| { if traits::overlapping_impls(&infcx, impl1_def_id, impl2_def_id).is_some() { self.check_for_common_items_in_impls(impl1_def_id, impl2_def_id) @@ -94,10 +99,12 @@ impl<'cx, 'tcx> OverlapChecker<'cx, 'tcx> { } } -impl<'cx, 'tcx,'v> intravisit::Visitor<'v> for OverlapChecker<'cx, 'tcx> { +impl<'cx, 'tcx, 'v> intravisit::Visitor<'v> for OverlapChecker<'cx, 'tcx> { fn visit_item(&mut self, item: &'v hir::Item) { match item.node { - hir::ItemEnum(..) | hir::ItemStruct(..) | hir::ItemUnion(..) => { + hir::ItemEnum(..) | + hir::ItemStruct(..) | + hir::ItemUnion(..) => { let type_def_id = self.tcx.map.local_def_id(item.id); self.check_for_overlapping_inherent_impls(type_def_id); } @@ -111,12 +118,14 @@ impl<'cx, 'tcx,'v> intravisit::Visitor<'v> for OverlapChecker<'cx, 'tcx> { let prev_default_impl = self.default_impls.insert(trait_ref.def_id, item.id); if let Some(prev_id) = prev_default_impl { - let mut err = struct_span_err!( - self.tcx.sess, - self.tcx.span_of_impl(impl_def_id).unwrap(), E0521, - "redundant default implementations of trait `{}`:", - trait_ref); - err.span_note(self.tcx.span_of_impl(self.tcx.map.local_def_id(prev_id)) + let mut err = struct_span_err!(self.tcx.sess, + self.tcx.span_of_impl(impl_def_id).unwrap(), + E0521, + "redundant default implementations of trait \ + `{}`:", + trait_ref); + err.span_note(self.tcx + .span_of_impl(self.tcx.map.local_def_id(prev_id)) .unwrap(), "redundant implementation is here:"); err.emit(); @@ -127,8 +136,8 @@ impl<'cx, 'tcx,'v> intravisit::Visitor<'v> for OverlapChecker<'cx, 'tcx> { let trait_ref = self.tcx.impl_trait_ref(impl_def_id).unwrap(); let trait_def_id = trait_ref.def_id; - let _task = self.tcx.dep_graph.in_task( - DepNode::CoherenceOverlapCheck(trait_def_id)); + let _task = + self.tcx.dep_graph.in_task(DepNode::CoherenceOverlapCheck(trait_def_id)); let def = self.tcx.lookup_trait_def(trait_def_id); @@ -137,17 +146,19 @@ impl<'cx, 'tcx,'v> intravisit::Visitor<'v> for OverlapChecker<'cx, 'tcx> { // insertion failed due to overlap if let Err(overlap) = insert_result { - let mut err = struct_span_err!( - self.tcx.sess, self.tcx.span_of_impl(impl_def_id).unwrap(), E0119, - "conflicting implementations of trait `{}`{}:", - overlap.trait_desc, - overlap.self_desc.clone().map_or(String::new(), - |ty| format!(" for type `{}`", ty))); + let mut err = struct_span_err!(self.tcx.sess, + self.tcx.span_of_impl(impl_def_id).unwrap(), + E0119, + "conflicting implementations of trait `{}`{}:", + overlap.trait_desc, + overlap.self_desc.clone().map_or(String::new(), + |ty| { + format!(" for type `{}`", ty) + })); match self.tcx.span_of_impl(overlap.with_impl) { Ok(span) => { - err.span_label(span, - &format!("first implementation here")); + err.span_label(span, &format!("first implementation here")); err.span_label(self.tcx.span_of_impl(impl_def_id).unwrap(), &format!("conflicting implementation{}", overlap.self_desc @@ -155,8 +166,7 @@ impl<'cx, 'tcx,'v> intravisit::Visitor<'v> for OverlapChecker<'cx, 'tcx> { |ty| format!(" for `{}`", ty)))); } Err(cname) => { - err.note(&format!("conflicting implementation in crate `{}`", - cname)); + err.note(&format!("conflicting implementation in crate `{}`", cname)); } } @@ -177,7 +187,9 @@ impl<'cx, 'tcx,'v> intravisit::Visitor<'v> for OverlapChecker<'cx, 'tcx> { 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, + span_err!(self.tcx.sess, + item.span, + E0371, "the object type `{}` automatically \ implements the trait `{}`", trait_ref.self_ty(), diff --git a/src/librustc_typeck/coherence/unsafety.rs b/src/librustc_typeck/coherence/unsafety.rs index cdf5478e69..cca6c88430 100644 --- a/src/librustc_typeck/coherence/unsafety.rs +++ b/src/librustc_typeck/coherence/unsafety.rs @@ -13,28 +13,34 @@ use rustc::ty::TyCtxt; use rustc::hir::intravisit; -use rustc::hir; +use rustc::hir::{self, Unsafety}; pub fn check<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>) { let mut orphan = UnsafetyChecker { tcx: tcx }; tcx.map.krate().visit_all_items(&mut orphan); } -struct UnsafetyChecker<'cx, 'tcx:'cx> { - tcx: TyCtxt<'cx, 'tcx, 'tcx> +struct UnsafetyChecker<'cx, 'tcx: 'cx> { + tcx: TyCtxt<'cx, 'tcx, 'tcx>, } impl<'cx, 'tcx, 'v> UnsafetyChecker<'cx, 'tcx> { - fn check_unsafety_coherence(&mut self, item: &'v hir::Item, + fn check_unsafety_coherence(&mut self, + item: &'v hir::Item, + impl_generics: Option<&hir::Generics>, unsafety: hir::Unsafety, polarity: hir::ImplPolarity) { match self.tcx.impl_trait_ref(self.tcx.map.local_def_id(item.id)) { None => { // Inherent impl. match unsafety { - hir::Unsafety::Normal => { /* OK */ } + hir::Unsafety::Normal => { + // OK + } hir::Unsafety::Unsafe => { - span_err!(self.tcx.sess, item.span, E0197, + span_err!(self.tcx.sess, + item.span, + E0197, "inherent impls cannot be declared as unsafe"); } } @@ -42,32 +48,45 @@ impl<'cx, 'tcx, 'v> UnsafetyChecker<'cx, 'tcx> { Some(trait_ref) => { let trait_def = self.tcx.lookup_trait_def(trait_ref.def_id); - match (trait_def.unsafety, unsafety, polarity) { - (hir::Unsafety::Unsafe, - hir::Unsafety::Unsafe, hir::ImplPolarity::Negative) => { - span_err!(self.tcx.sess, item.span, E0198, + let unsafe_attr = impl_generics.and_then(|g| g.carries_unsafe_attr()); + match (trait_def.unsafety, unsafe_attr, unsafety, polarity) { + (_, _, Unsafety::Unsafe, hir::ImplPolarity::Negative) => { + span_err!(self.tcx.sess, + item.span, + E0198, "negative implementations are not unsafe"); } - (hir::Unsafety::Normal, hir::Unsafety::Unsafe, _) => { - span_err!(self.tcx.sess, item.span, E0199, + (Unsafety::Normal, None, Unsafety::Unsafe, _) => { + span_err!(self.tcx.sess, + item.span, + E0199, "implementing the trait `{}` is not unsafe", trait_ref); } - (hir::Unsafety::Unsafe, - hir::Unsafety::Normal, hir::ImplPolarity::Positive) => { - span_err!(self.tcx.sess, item.span, E0200, + (Unsafety::Unsafe, _, Unsafety::Normal, hir::ImplPolarity::Positive) => { + span_err!(self.tcx.sess, + item.span, + E0200, "the trait `{}` requires an `unsafe impl` declaration", trait_ref); } - (hir::Unsafety::Unsafe, - hir::Unsafety::Normal, hir::ImplPolarity::Negative) | - (hir::Unsafety::Unsafe, - hir::Unsafety::Unsafe, hir::ImplPolarity::Positive) | - (hir::Unsafety::Normal, hir::Unsafety::Normal, _) => { - /* OK */ + (Unsafety::Normal, Some(g), Unsafety::Normal, hir::ImplPolarity::Positive) => + { + span_err!(self.tcx.sess, + item.span, + E0569, + "requires an `unsafe impl` declaration due to `#[{}]` attribute", + g.attr_name()); + } + + (_, _, Unsafety::Normal, hir::ImplPolarity::Negative) | + (Unsafety::Unsafe, _, Unsafety::Unsafe, hir::ImplPolarity::Positive) | + (Unsafety::Normal, Some(_), Unsafety::Unsafe, hir::ImplPolarity::Positive) | + (Unsafety::Normal, None, Unsafety::Normal, _) => { + // OK } } } @@ -75,16 +94,16 @@ impl<'cx, 'tcx, 'v> UnsafetyChecker<'cx, 'tcx> { } } -impl<'cx, 'tcx,'v> intravisit::Visitor<'v> for UnsafetyChecker<'cx, 'tcx> { +impl<'cx, 'tcx, 'v> intravisit::Visitor<'v> for UnsafetyChecker<'cx, 'tcx> { fn visit_item(&mut self, item: &'v hir::Item) { match item.node { hir::ItemDefaultImpl(unsafety, _) => { - self.check_unsafety_coherence(item, unsafety, hir::ImplPolarity::Positive); + self.check_unsafety_coherence(item, None, unsafety, hir::ImplPolarity::Positive); } - hir::ItemImpl(unsafety, polarity, ..) => { - self.check_unsafety_coherence(item, unsafety, polarity); + hir::ItemImpl(unsafety, polarity, ref generics, ..) => { + self.check_unsafety_coherence(item, Some(generics), unsafety, polarity); } - _ => { } + _ => {} } } } diff --git a/src/librustc_typeck/collect.rs b/src/librustc_typeck/collect.rs index e5d4d4a9da..0e0f5cb1a7 100644 --- a/src/librustc_typeck/collect.rs +++ b/src/librustc_typeck/collect.rs @@ -68,7 +68,6 @@ use rustc_const_eval::{eval_const_expr_partial, report_const_eval_err}; use rustc::ty::subst::Substs; use rustc::ty::{ToPredicate, ImplContainer, ImplOrTraitItemContainer, TraitContainer}; use rustc::ty::{self, AdtKind, ToPolyTraitRef, Ty, TyCtxt, TypeScheme}; -use rustc::ty::{VariantKind}; use rustc::ty::util::IntTypeExt; use rscope::*; use rustc::dep_graph::DepNode; @@ -87,7 +86,7 @@ use syntax::parse::token::keywords; use syntax_pos::Span; use rustc::hir::{self, intravisit, map as hir_map, print as pprust}; -use rustc::hir::def::Def; +use rustc::hir::def::{Def, CtorKind}; use rustc::hir::def_id::DefId; /////////////////////////////////////////////////////////////////////////// @@ -157,13 +156,10 @@ impl<'a,'tcx> CrateCtxt<'a,'tcx> { { { let mut stack = self.stack.borrow_mut(); - match stack.iter().enumerate().rev().find(|&(_, r)| *r == request) { - None => { } - Some((i, _)) => { - let cycle = &stack[i..]; - self.report_cycle(span, cycle); - return Err(ErrorReported); - } + if let Some((i, _)) = stack.iter().enumerate().rev().find(|&(_, r)| *r == request) { + let cycle = &stack[i..]; + self.report_cycle(span, cycle); + return Err(ErrorReported); } stack.push(request); } @@ -987,9 +983,9 @@ fn convert_variant_ctor<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>, let tcx = ccx.tcx; let def_id = tcx.map.local_def_id(ctor_id); generics_of_def_id(ccx, def_id); - let ctor_ty = match variant.kind { - VariantKind::Unit | VariantKind::Struct => scheme.ty, - VariantKind::Tuple => { + let ctor_ty = match variant.ctor_kind { + CtorKind::Fictive | CtorKind::Const => scheme.ty, + CtorKind::Fn => { let inputs: Vec<_> = variant.fields .iter() @@ -1066,7 +1062,7 @@ fn convert_struct_variant<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>, name: name, disr_val: disr_val, fields: fields, - kind: VariantKind::from_variant_data(def), + ctor_kind: CtorKind::from_hir(def), } } @@ -1164,10 +1160,12 @@ fn convert_enum_def<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>, } else if let Some(disr) = repr_type.disr_incr(tcx, prev_disr) { Some(disr) } else { - span_err!(tcx.sess, v.span, E0370, - "enum discriminant overflowed on value after {}; \ - set explicitly via {} = {} if that is desired outcome", - prev_disr.unwrap(), v.node.name, wrapped_disr); + struct_span_err!(tcx.sess, v.span, E0370, + "enum discriminant overflowed") + .span_label(v.span, &format!("overflowed on value after {}", prev_disr.unwrap())) + .note(&format!("explicitly set `{} = {}` if that is desired outcome", + v.node.name, wrapped_disr)) + .emit(); None }.unwrap_or(wrapped_disr); prev_disr = Some(disr); @@ -1389,7 +1387,7 @@ fn convert_trait_predicates<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>, it: &hir::Item) let bounds = match trait_item.node { hir::TypeTraitItem(ref bounds, _) => bounds, _ => { - return vec!().into_iter(); + return vec![].into_iter(); } }; @@ -1481,6 +1479,7 @@ fn generics_of_def_id<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>, default_def_id: tcx.map.local_def_id(parent), default: None, object_lifetime_default: ty::ObjectLifetimeDefault::BaseDefault, + pure_wrt_drop: false, }; tcx.ty_param_defs.borrow_mut().insert(param_id, def.clone()); opt_self = Some(def); @@ -1525,7 +1524,8 @@ fn generics_of_def_id<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>, def_id: tcx.map.local_def_id(l.lifetime.id), bounds: l.bounds.iter().map(|l| { ast_region_to_region(tcx, l) - }).collect() + }).collect(), + pure_wrt_drop: l.pure_wrt_drop, } }).collect::>(); @@ -1724,16 +1724,15 @@ fn add_unsized_bound<'gcx: 'tcx, 'tcx>(astconv: &AstConv<'gcx, 'tcx>, match unbound { Some(ref tpb) => { // FIXME(#8559) currently requires the unbound to be built-in. - let trait_def_id = tcx.expect_def(tpb.ref_id).def_id(); - match kind_id { - Ok(kind_id) if trait_def_id != kind_id => { + if let Ok(kind_id) = kind_id { + let trait_def = tcx.expect_def(tpb.ref_id); + if trait_def != Def::Trait(kind_id) { tcx.sess.span_warn(span, "default bound relaxed for a type parameter, but \ this does nothing because the given bound is not \ a default. Only `?Sized` is supported"); tcx.try_add_builtin_trait(kind_id, bounds); } - _ => {} } } _ if kind_id.is_ok() => { @@ -1925,6 +1924,7 @@ fn get_or_create_type_parameter_def<'a,'tcx>(ccx: &CrateCtxt<'a,'tcx>, default_def_id: ccx.tcx.map.local_def_id(parent), default: default, object_lifetime_default: object_lifetime_default, + pure_wrt_drop: param.pure_wrt_drop, }; if def.name == keywords::SelfType.name() { diff --git a/src/librustc_typeck/diagnostics.rs b/src/librustc_typeck/diagnostics.rs index 0d6b43b59c..be012d8976 100644 --- a/src/librustc_typeck/diagnostics.rs +++ b/src/librustc_typeck/diagnostics.rs @@ -458,7 +458,7 @@ Rust only supports variadic parameters for interoperability with C code in its FFI. As such, variadic parameters can only be used with functions which are using the C ABI. Examples of erroneous code: -```compile_fail,E0045 +```compile_fail #![feature(unboxed_closures)] extern "rust-call" { fn foo(x: u8, ...); } @@ -895,17 +895,14 @@ fn some_func(x: &mut i32) { E0071: r##" You tried to use structure-literal syntax to create an item that is -not a struct-style structure or enum variant. +not a structure or enum variant. Example of erroneous code: ```compile_fail,E0071 -enum Foo { FirstValue(i32) }; - -let u = Foo::FirstValue { value: 0 }; // error: Foo::FirstValue - // isn't a structure! -// or even simpler, if the name doesn't refer to a structure at all. -let t = u32 { value: 4 }; // error: `u32` does not name a structure. +type U32 = u32; +let t = U32 { value: 4 }; // error: expected struct, variant or union type, + // found builtin type `u32` ``` To fix this, ensure that the name was correctly spelled, and that @@ -1915,6 +1912,45 @@ More details can be found in [RFC 438]. [RFC 438]: https://github.com/rust-lang/rfcs/pull/438 "##, +E0182: r##" +You bound an associated type in an expression path which is not +allowed. + +Erroneous code example: + +```compile_fail,E0182 +trait Foo { + type A; + fn bar() -> isize; +} + +impl Foo for isize { + type A = usize; + fn bar() -> isize { 42 } +} + +// error: unexpected binding of associated item in expression path +let x: isize = Foo::::bar(); +``` + +To give a concrete type when using the Universal Function Call Syntax, +use "Type as Trait". Example: + +``` +trait Foo { + type A; + fn bar() -> isize; +} + +impl Foo for isize { + type A = usize; + fn bar() -> isize { 42 } +} + +let x: isize = ::bar(); // ok! +``` +"##, + E0184: r##" Explicitly implementing both Drop and Copy for a type is currently disallowed. This feature can make some sense in theory, but the current implementation is @@ -2752,6 +2788,30 @@ fn main() { ``` "##, +E0230: r##" +The trait has more type parameters specified than appear in its definition. + +Erroneous example code: + +```compile_fail,E0230 +#![feature(on_unimplemented)] +#[rustc_on_unimplemented = "Trait error on `{Self}` with `<{A},{B},{C}>`"] +// error: there is no type parameter C on trait TraitWithThreeParams +trait TraitWithThreeParams +{} +``` + +Include the correct number of type parameters and the compilation should +proceed: + +``` +#![feature(on_unimplemented)] +#[rustc_on_unimplemented = "Trait error on `{Self}` with `<{A},{B},{C}>`"] +trait TraitWithThreeParams // ok! +{} +``` +"##, + E0232: r##" The attribute must have a value. Erroneous code example: @@ -2819,6 +2879,26 @@ not a distinct static type. Likewise, it's not legal to attempt to behavior for specific enum variants. "##, +E0569: r##" +If an impl has a generic parameter with the `#[may_dangle]` attribute, then +that impl must be declared as an `unsafe impl. For example: + +```compile_fail,E0569 +#![feature(generic_param_attrs)] +#![feature(dropck_eyepatch)] + +struct Foo(X); +impl<#[may_dangle] X> Drop for Foo { + fn drop(&mut self) { } +} +``` + +In this example, we are asserting that the destructor for `Foo` will not +access any data of type `X`, and require this assertion to be true for +overall safety in our program. The compiler does not currently attempt to +verify this assertion; therefore we must tag this `impl` as unsafe. +"##, + E0318: r##" Default impls for a trait must be located in the same crate where the trait was defined. For more information see the [opt-in builtin traits RFC](https://github @@ -3567,6 +3647,44 @@ fn together_we_will_rule_the_galaxy(son: &A) {} // Ok! ``` "##, +E0399: r##" +You implemented a trait, overriding one or more of its associated types but did +not reimplement its default methods. + +Example of erroneous code: + +```compile_fail,E0399 +#![feature(associated_type_defaults)] + +pub trait Foo { + type Assoc = u8; + fn bar(&self) {} +} + +impl Foo for i32 { + // error - the following trait items need to be reimplemented as + // `Assoc` was overridden: `bar` + type Assoc = i32; +} +``` + +To fix this, add an implementation for each default method from the trait: + +``` +#![feature(associated_type_defaults)] + +pub trait Foo { + type Assoc = u8; + fn bar(&self) {} +} + +impl Foo for i32 { + type Assoc = i32; + fn bar(&self) {} // ok! +} +``` +"##, + E0439: r##" The length of the platform-intrinsic function `simd_shuffle` wasn't specified. Erroneous code example: @@ -4035,6 +4153,16 @@ let s = Simba { mother: 1, father: 0 }; // ok! ``` "##, +E0570: r##" +The requested ABI is unsupported by the current target. + +The rust compiler maintains for each target a blacklist of ABIs unsupported on +that target. If an ABI is present in such a list this usually means that the +target / ABI combination is currently unsupported by llvm. + +If necessary, you can circumvent this check using custom target specifications. +"##, + } register_diagnostics! { @@ -4054,7 +4182,6 @@ register_diagnostics! { // E0168, // E0173, // manual implementations of unboxed closure traits are experimental // E0174, - E0182, E0183, // E0187, // can't infer the kind of the closure // E0188, // can not cast an immutable reference to a mutable pointer @@ -4078,7 +4205,6 @@ register_diagnostics! { E0226, // only a single explicit lifetime bound is permitted E0227, // ambiguous lifetime bound, explicit lifetime bound required E0228, // explicit lifetime bound required - E0230, // there is no type parameter on trait E0231, // only named substitution parameters are allowed // E0233, // E0234, @@ -4100,8 +4226,6 @@ register_diagnostics! { // E0372, // coherence not object safe E0377, // the trait `CoerceUnsized` may only be implemented for a coercion // between structures with the same definition - E0399, // trait items need to be implemented because the associated - // type `{}` was overridden E0436, // functional record update requires a struct E0521, // redundant default implementations of trait E0533, // `{}` does not name a unit variant, unit struct or a constant diff --git a/src/librustc_typeck/lib.rs b/src/librustc_typeck/lib.rs index cb9b162cab..d7573c7a7b 100644 --- a/src/librustc_typeck/lib.rs +++ b/src/librustc_typeck/lib.rs @@ -77,7 +77,7 @@ This API is completely unstable and subject to change. #![feature(box_patterns)] #![feature(box_syntax)] #![feature(conservative_impl_trait)] -#![feature(dotdot_in_tuple_patterns)] +#![cfg_attr(stage0, feature(dotdot_in_tuple_patterns))] #![feature(quote)] #![feature(rustc_diagnostic_macros)] #![feature(rustc_private)] @@ -106,7 +106,7 @@ pub use rustc::util; use dep_graph::DepNode; use hir::map as hir_map; -use rustc::infer::TypeOrigin; +use rustc::infer::{InferOk, TypeOrigin}; use rustc::ty::subst::Substs; use rustc::ty::{self, Ty, TyCtxt, TypeFoldable}; use rustc::traits::{self, Reveal}; @@ -194,15 +194,20 @@ fn require_c_abi_if_variadic(tcx: TyCtxt, fn require_same_types<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>, origin: TypeOrigin, - t1: Ty<'tcx>, - t2: Ty<'tcx>) + expected: Ty<'tcx>, + actual: Ty<'tcx>) -> bool { ccx.tcx.infer_ctxt(None, None, Reveal::NotSpecializable).enter(|infcx| { - if let Err(err) = infcx.eq_types(false, origin.clone(), t1, t2) { - infcx.report_mismatched_types(origin, t1, t2, err); - false - } else { - true + match infcx.eq_types(false, origin.clone(), expected, actual) { + Ok(InferOk { obligations, .. }) => { + // FIXME(#32730) propagate obligations + assert!(obligations.is_empty()); + true + } + Err(err) => { + infcx.report_mismatched_types(origin, expected, actual, err); + false + } } }) } @@ -211,7 +216,7 @@ fn check_main_fn_ty(ccx: &CrateCtxt, main_id: ast::NodeId, main_span: Span) { let tcx = ccx.tcx; - let main_t = tcx.node_id_to_type(main_id); + let main_t = tcx.tables().node_id_to_type(main_id); match main_t.sty { ty::TyFnDef(..) => { match tcx.map.find(main_id) { @@ -233,7 +238,7 @@ fn check_main_fn_ty(ccx: &CrateCtxt, _ => () } let main_def_id = tcx.map.local_def_id(main_id); - let substs = Substs::empty(tcx); + let substs = tcx.intern_substs(&[]); let se_ty = tcx.mk_fn_def(main_def_id, substs, tcx.mk_bare_fn(ty::BareFnTy { unsafety: hir::Unsafety::Normal, @@ -248,8 +253,8 @@ fn check_main_fn_ty(ccx: &CrateCtxt, require_same_types( ccx, TypeOrigin::MainFunctionType(main_span), - main_t, - se_ty); + se_ty, + main_t); } _ => { span_bug!(main_span, @@ -263,7 +268,7 @@ fn check_start_fn_ty(ccx: &CrateCtxt, start_id: ast::NodeId, start_span: Span) { let tcx = ccx.tcx; - let start_t = tcx.node_id_to_type(start_id); + let start_t = tcx.tables().node_id_to_type(start_id); match start_t.sty { ty::TyFnDef(..) => { match tcx.map.find(start_id) { @@ -285,16 +290,16 @@ fn check_start_fn_ty(ccx: &CrateCtxt, } let start_def_id = ccx.tcx.map.local_def_id(start_id); - let substs = Substs::empty(tcx); + let substs = tcx.intern_substs(&[]); let se_ty = tcx.mk_fn_def(start_def_id, substs, tcx.mk_bare_fn(ty::BareFnTy { unsafety: hir::Unsafety::Normal, abi: Abi::Rust, sig: ty::Binder(ty::FnSig { - inputs: vec!( + inputs: vec![ tcx.types.isize, tcx.mk_imm_ptr(tcx.mk_imm_ptr(tcx.types.u8)) - ), + ], output: tcx.types.isize, variadic: false, }), @@ -303,8 +308,8 @@ fn check_start_fn_ty(ccx: &CrateCtxt, require_same_types( ccx, TypeOrigin::StartFunctionType(start_span), - start_t, - se_ty); + se_ty, + start_t); } _ => { span_bug!(start_span, diff --git a/src/librustc_typeck/variance/README.md b/src/librustc_typeck/variance/README.md index 94d1ff91c3..ac785e4058 100644 --- a/src/librustc_typeck/variance/README.md +++ b/src/librustc_typeck/variance/README.md @@ -1,3 +1,5 @@ +## Variance of type and lifetime parameters + This file infers the variance of type and lifetime parameters. The algorithm is taken from Section 4 of the paper "Taming the Wildcards: Combining Definition- and Use-Site Variance" published in PLDI'11 and @@ -52,11 +54,11 @@ These indicate that (1) the variance of A must be at most covariant; 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) + * Top (bivariant) + - + + o Bottom (invariant) -Based on this lattice, the solution V(A)=+, V(B)=-, V(C)=o is the +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. @@ -68,11 +70,11 @@ 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 +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` +> 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)`. @@ -267,7 +269,7 @@ 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, @@ -291,9 +293,9 @@ impl Identity for T { type Out = T; ... } Now if I have `<&'static () as Identity>::Out`, this can be validly derived as `&'a ()` for any `'a`: - <&'a () as Identity> <: <&'static () as Identity> - if &'static () < : &'a () -- Identity is contravariant in Self - if 'static : 'a -- Subtyping rules for relations + <&'a () as Identity> <: <&'static () as Identity> + if &'static () < : &'a () -- Identity is contravariant in Self + if 'static : 'a -- Subtyping rules for relations This change otoh means that `<'static () as Identity>::Out` is always `&'static ()` (which might then be upcast to `'a ()`, diff --git a/src/librustc_unicode/char.rs b/src/librustc_unicode/char.rs index 5a0c27d9c6..702d7d8b4b 100644 --- a/src/librustc_unicode/char.rs +++ b/src/librustc_unicode/char.rs @@ -37,7 +37,7 @@ use tables::{conversions, derived_property, general_category, property}; #[stable(feature = "rust1", since = "1.0.0")] pub use core::char::{MAX, from_digit, from_u32, from_u32_unchecked}; #[stable(feature = "rust1", since = "1.0.0")] -pub use core::char::{EncodeUtf16, EncodeUtf8, EscapeDebug, EscapeDefault, EscapeUnicode}; +pub use core::char::{EscapeDebug, EscapeDefault, EscapeUnicode}; // unstable reexports #[unstable(feature = "try_from", issue = "33417")] @@ -435,50 +435,96 @@ impl char { C::len_utf16(self) } - /// Returns an iterator over the bytes of this character as UTF-8. + /// Encodes this character as UTF-8 into the provided byte buffer, + /// and then returns the subslice of the buffer that contains the encoded character. /// - /// The returned iterator also has an `as_slice()` method to view the - /// encoded bytes as a byte slice. + /// # Panics + /// + /// Panics if the buffer is not large enough. + /// A buffer of length four is large enough to encode any `char`. /// /// # Examples /// + /// In both of these examples, 'ß' takes two bytes to encode. + /// /// ``` /// #![feature(unicode)] /// - /// let iterator = 'ß'.encode_utf8(); - /// assert_eq!(iterator.as_slice(), [0xc3, 0x9f]); + /// let mut b = [0; 2]; /// - /// for (i, byte) in iterator.enumerate() { - /// println!("byte {}: {:x}", i, byte); - /// } + /// let result = 'ß'.encode_utf8(&mut b); + /// + /// assert_eq!(result, "ß"); + /// + /// assert_eq!(result.len(), 2); + /// ``` + /// + /// A buffer that's too small: + /// + /// ``` + /// #![feature(unicode)] + /// use std::thread; + /// + /// let result = thread::spawn(|| { + /// let mut b = [0; 1]; + /// + /// // this panics + /// 'ß'.encode_utf8(&mut b); + /// }).join(); + /// + /// assert!(result.is_err()); /// ``` - #[unstable(feature = "unicode", issue = "27784")] + #[unstable(feature = "unicode", + reason = "pending decision about Iterator/Writer/Reader", + issue = "27784")] #[inline] - pub fn encode_utf8(self) -> EncodeUtf8 { - C::encode_utf8(self) + pub fn encode_utf8(self, dst: &mut [u8]) -> &mut str { + C::encode_utf8(self, dst) } - /// Returns an iterator over the `u16` entries of this character as UTF-16. + /// Encodes this character as UTF-16 into the provided `u16` buffer, + /// and then returns the subslice of the buffer that contains the encoded character. /// - /// The returned iterator also has an `as_slice()` method to view the - /// encoded form as a slice. + /// # Panics + /// + /// Panics if the buffer is not large enough. + /// A buffer of length 2 is large enough to encode any `char`. /// /// # Examples /// + /// In both of these examples, '𝕊' takes two `u16`s to encode. + /// /// ``` /// #![feature(unicode)] /// - /// let iterator = '𝕊'.encode_utf16(); - /// assert_eq!(iterator.as_slice(), [0xd835, 0xdd4a]); + /// let mut b = [0; 2]; /// - /// for (i, val) in iterator.enumerate() { - /// println!("entry {}: {:x}", i, val); - /// } + /// let result = '𝕊'.encode_utf16(&mut b); + /// + /// assert_eq!(result.len(), 2); /// ``` - #[unstable(feature = "unicode", issue = "27784")] + /// + /// A buffer that's too small: + /// + /// ``` + /// #![feature(unicode)] + /// use std::thread; + /// + /// let result = thread::spawn(|| { + /// let mut b = [0; 1]; + /// + /// // this panics + /// '𝕊'.encode_utf16(&mut b); + /// }).join(); + /// + /// assert!(result.is_err()); + /// ``` + #[unstable(feature = "unicode", + reason = "pending decision about Iterator/Writer/Reader", + issue = "27784")] #[inline] - pub fn encode_utf16(self) -> EncodeUtf16 { - C::encode_utf16(self) + pub fn encode_utf16(self, dst: &mut [u16]) -> &mut [u16] { + C::encode_utf16(self, dst) } /// Returns true if this `char` is an alphabetic code point, and false if not. diff --git a/src/librustc_unicode/u_str.rs b/src/librustc_unicode/u_str.rs index eb5b6feeb7..1c7894794c 100644 --- a/src/librustc_unicode/u_str.rs +++ b/src/librustc_unicode/u_str.rs @@ -157,13 +157,13 @@ impl Iterator for Utf16Encoder return Some(tmp); } + let mut buf = [0; 2]; self.chars.next().map(|ch| { - let n = CharExt::encode_utf16(ch); - let n = n.as_slice(); - if n.len() == 2 { - self.extra = n[1]; + let n = CharExt::encode_utf16(ch, &mut buf).len(); + if n == 2 { + self.extra = buf[1]; } - n[0] + buf[0] }) } @@ -181,6 +181,7 @@ impl Iterator for Utf16Encoder impl FusedIterator for Utf16Encoder where I: FusedIterator {} +#[stable(feature = "split_whitespace", since = "1.1.0")] impl<'a> Iterator for SplitWhitespace<'a> { type Item = &'a str; @@ -188,6 +189,8 @@ impl<'a> Iterator for SplitWhitespace<'a> { self.inner.next() } } + +#[stable(feature = "split_whitespace", since = "1.1.0")] impl<'a> DoubleEndedIterator for SplitWhitespace<'a> { fn next_back(&mut self) -> Option<&'a str> { self.inner.next_back() diff --git a/src/librustdoc/clean/inline.rs b/src/librustdoc/clean/inline.rs index c4d6ff43ef..31497b6bd3 100644 --- a/src/librustdoc/clean/inline.rs +++ b/src/librustdoc/clean/inline.rs @@ -15,11 +15,10 @@ use std::iter::once; use syntax::ast; use rustc::hir; -use rustc::hir::def::Def; +use rustc::hir::def::{Def, CtorKind}; use rustc::hir::def_id::DefId; -use rustc::hir::map::DefPathData; use rustc::hir::print as pprust; -use rustc::ty::{self, TyCtxt, VariantKind}; +use rustc::ty::{self, TyCtxt}; use rustc::util::nodemap::FnvHashSet; use rustc_const_eval::lookup_const_by_id; @@ -73,49 +72,50 @@ fn try_inline_def<'a, 'tcx>(cx: &DocContext, tcx: TyCtxt<'a, 'tcx, 'tcx>, let did = def.def_id(); let inner = match def { Def::Trait(did) => { - record_extern_fqn(cx, did, clean::TypeTrait); + record_extern_fqn(cx, did, clean::TypeKind::Trait); ret.extend(build_impls(cx, tcx, did)); clean::TraitItem(build_external_trait(cx, tcx, did)) } Def::Fn(did) => { - record_extern_fqn(cx, did, clean::TypeFunction); + record_extern_fqn(cx, did, clean::TypeKind::Function); clean::FunctionItem(build_external_function(cx, tcx, did)) } - Def::Struct(did) - // If this is a struct constructor, we skip it - if tcx.def_key(did).disambiguated_data.data != DefPathData::StructCtor => { - record_extern_fqn(cx, did, clean::TypeStruct); + Def::Struct(did) => { + record_extern_fqn(cx, did, clean::TypeKind::Struct); ret.extend(build_impls(cx, tcx, did)); clean::StructItem(build_struct(cx, tcx, did)) } Def::Union(did) => { - record_extern_fqn(cx, did, clean::TypeUnion); + record_extern_fqn(cx, did, clean::TypeKind::Union); ret.extend(build_impls(cx, tcx, did)); clean::UnionItem(build_union(cx, tcx, did)) } Def::TyAlias(did) => { - record_extern_fqn(cx, did, clean::TypeTypedef); + record_extern_fqn(cx, did, clean::TypeKind::Typedef); ret.extend(build_impls(cx, tcx, did)); clean::TypedefItem(build_type_alias(cx, tcx, did), false) } Def::Enum(did) => { - record_extern_fqn(cx, did, clean::TypeEnum); + record_extern_fqn(cx, did, clean::TypeKind::Enum); ret.extend(build_impls(cx, tcx, did)); clean::EnumItem(build_enum(cx, tcx, did)) } // Assume that the enum type is reexported next to the variant, and // variants don't show up in documentation specially. - Def::Variant(..) => return Some(Vec::new()), + // Similarly, consider that struct type is reexported next to its constructor. + Def::Variant(..) | + Def::VariantCtor(..) | + Def::StructCtor(..) => return Some(Vec::new()), Def::Mod(did) => { - record_extern_fqn(cx, did, clean::TypeModule); + record_extern_fqn(cx, did, clean::TypeKind::Module); clean::ModuleItem(build_module(cx, tcx, did)) } Def::Static(did, mtbl) => { - record_extern_fqn(cx, did, clean::TypeStatic); + record_extern_fqn(cx, did, clean::TypeKind::Static); clean::StaticItem(build_static(cx, tcx, did, mtbl)) } - Def::Const(did) | Def::AssociatedConst(did) => { - record_extern_fqn(cx, did, clean::TypeConst); + Def::Const(did) => { + record_extern_fqn(cx, did, clean::TypeKind::Const); clean::ConstantItem(build_const(cx, tcx, did)) } _ => return None, @@ -219,10 +219,10 @@ fn build_struct<'a, 'tcx>(cx: &DocContext, tcx: TyCtxt<'a, 'tcx, 'tcx>, let variant = tcx.lookup_adt_def(did).struct_variant(); clean::Struct { - struct_type: match variant.kind { - VariantKind::Struct => doctree::Plain, - VariantKind::Tuple => doctree::Tuple, - VariantKind::Unit => doctree::Unit, + struct_type: match variant.ctor_kind { + CtorKind::Fictive => doctree::Plain, + CtorKind::Fn => doctree::Tuple, + CtorKind::Const => doctree::Unit, }, generics: (t.generics, &predicates).clean(cx), fields: variant.fields.clean(cx), @@ -301,8 +301,8 @@ pub fn build_impls<'a, 'tcx>(cx: &DocContext, tcx.lang_items.char_impl(), tcx.lang_items.str_impl(), tcx.lang_items.slice_impl(), - tcx.lang_items.slice_impl(), - tcx.lang_items.const_ptr_impl() + tcx.lang_items.const_ptr_impl(), + tcx.lang_items.mut_ptr_impl(), ]; for def_id in primitive_impls.iter().filter_map(|&def_id| def_id) { @@ -498,12 +498,11 @@ fn build_module<'a, 'tcx>(cx: &DocContext, tcx: TyCtxt<'a, 'tcx, 'tcx>, // visit each node at most once. let mut visited = FnvHashSet(); for item in tcx.sess.cstore.item_children(did) { - if tcx.sess.cstore.visibility(item.def_id) == ty::Visibility::Public { - if !visited.insert(item.def_id) { continue } - if let Some(def) = tcx.sess.cstore.describe_def(item.def_id) { - if let Some(i) = try_inline_def(cx, tcx, def) { - items.extend(i) - } + let def_id = item.def.def_id(); + if tcx.sess.cstore.visibility(def_id) == ty::Visibility::Public { + if !visited.insert(def_id) { continue } + if let Some(i) = try_inline_def(cx, tcx, item.def) { + items.extend(i) } } } @@ -577,7 +576,7 @@ fn filter_non_trait_generics(trait_did: DefId, mut g: clean::Generics) _ => true, } }); - return g; + g } /// Supertrait bounds for a trait are also listed in the generics coming from diff --git a/src/librustdoc/clean/mod.rs b/src/librustdoc/clean/mod.rs index 0ae059509b..265b66b01e 100644 --- a/src/librustdoc/clean/mod.rs +++ b/src/librustdoc/clean/mod.rs @@ -12,10 +12,7 @@ //! that clean them. pub use self::Type::*; -pub use self::TypeKind::*; -pub use self::VariantKind::*; pub use self::Mutability::*; -pub use self::Import::*; pub use self::ItemEnum::*; pub use self::Attribute::*; pub use self::TyParamBound::*; @@ -35,7 +32,7 @@ use syntax_pos::{self, DUMMY_SP, Pos}; use rustc_trans::back::link; use rustc::middle::privacy::AccessLevels; use rustc::middle::resolve_lifetime::DefRegion::*; -use rustc::hir::def::Def; +use rustc::hir::def::{Def, CtorKind}; use rustc::hir::def_id::{self, DefId, DefIndex, CRATE_DEF_INDEX}; use rustc::hir::print as pprust; use rustc::ty::subst::Substs; @@ -240,7 +237,7 @@ impl Clean for CrateNum { let root = DefId { krate: self.0, index: CRATE_DEF_INDEX }; cx.tcx_opt().map(|tcx| { for item in tcx.sess.cstore.item_children(root) { - let attrs = inline::load_attrs(cx, tcx, item.def_id); + let attrs = inline::load_attrs(cx, tcx, item.def.def_id()); PrimitiveType::find(&attrs).map(|prim| primitives.push(prim)); } }); @@ -283,34 +280,34 @@ impl Item { } } pub fn is_mod(&self) -> bool { - ItemType::from(self) == ItemType::Module + self.type_() == ItemType::Module } pub fn is_trait(&self) -> bool { - ItemType::from(self) == ItemType::Trait + self.type_() == ItemType::Trait } pub fn is_struct(&self) -> bool { - ItemType::from(self) == ItemType::Struct + self.type_() == ItemType::Struct } pub fn is_enum(&self) -> bool { - ItemType::from(self) == ItemType::Module + self.type_() == ItemType::Module } pub fn is_fn(&self) -> bool { - ItemType::from(self) == ItemType::Function + self.type_() == ItemType::Function } pub fn is_associated_type(&self) -> bool { - ItemType::from(self) == ItemType::AssociatedType + self.type_() == ItemType::AssociatedType } pub fn is_associated_const(&self) -> bool { - ItemType::from(self) == ItemType::AssociatedConst + self.type_() == ItemType::AssociatedConst } pub fn is_method(&self) -> bool { - ItemType::from(self) == ItemType::Method + self.type_() == ItemType::Method } pub fn is_ty_method(&self) -> bool { - ItemType::from(self) == ItemType::TyMethod + self.type_() == ItemType::TyMethod } pub fn is_primitive(&self) -> bool { - ItemType::from(self) == ItemType::Primitive + self.type_() == ItemType::Primitive } pub fn is_stripped(&self) -> bool { match self.inner { StrippedItem(..) => true, _ => false } @@ -319,7 +316,7 @@ impl Item { match self.inner { StructItem(ref _struct) => Some(_struct.fields_stripped), UnionItem(ref union) => Some(union.fields_stripped), - VariantItem(Variant { kind: StructVariant(ref vstruct)} ) => { + VariantItem(Variant { kind: VariantKind::Struct(ref vstruct)} ) => { Some(vstruct.fields_stripped) }, _ => None, @@ -342,6 +339,11 @@ impl Item { pub fn stable_since(&self) -> Option<&str> { self.stability.as_ref().map(|s| &s.since[..]) } + + /// Returns a documentation-level item type from the item. + pub fn type_(&self) -> ItemType { + ItemType::from(self) + } } #[derive(Clone, RustcEncodable, RustcDecodable, Debug)] @@ -668,7 +670,7 @@ impl Clean for ty::BuiltinBound { Some(tcx) => tcx, None => return RegionBound(Lifetime::statik()) }; - let empty = Substs::empty(tcx); + let empty = tcx.intern_substs(&[]); let (did, path) = match *self { ty::BoundSend => (tcx.lang_items.send_trait().unwrap(), @@ -683,7 +685,7 @@ impl Clean for ty::BuiltinBound { (tcx.lang_items.sync_trait().unwrap(), external_path(cx, "Sync", None, false, vec![], empty)), }; - inline::record_extern_fqn(cx, did, TypeTrait); + inline::record_extern_fqn(cx, did, TypeKind::Trait); TraitBound(PolyTrait { trait_: ResolvedPath { path: path, @@ -702,7 +704,7 @@ impl<'tcx> Clean for ty::TraitRef<'tcx> { Some(tcx) => tcx, None => return RegionBound(Lifetime::statik()) }; - inline::record_extern_fqn(cx, self.def_id, TypeTrait); + inline::record_extern_fqn(cx, self.def_id, TypeKind::Trait); let path = external_path(cx, &tcx.item_name(self.def_id).as_str(), Some(self.def_id), true, vec![], self.substs); @@ -760,7 +762,7 @@ impl Lifetime { pub fn get_ref<'a>(&'a self) -> &'a str { let Lifetime(ref s) = *self; let s: &'a str = s; - return s; + s } pub fn statik() -> Lifetime { @@ -1125,7 +1127,7 @@ pub struct FnDecl { impl FnDecl { pub fn has_self(&self) -> bool { - return self.inputs.values.len() > 0 && self.inputs.values[0].name == "self"; + self.inputs.values.len() > 0 && self.inputs.values[0].name == "self" } pub fn self_type(&self) -> Option { @@ -1475,16 +1477,16 @@ pub enum PrimitiveType { #[derive(Clone, RustcEncodable, RustcDecodable, Copy, Debug)] pub enum TypeKind { - TypeEnum, - TypeFunction, - TypeModule, - TypeConst, - TypeStatic, - TypeStruct, - TypeUnion, - TypeTrait, - TypeVariant, - TypeTypedef, + Enum, + Function, + Module, + Const, + Static, + Struct, + Union, + Trait, + Variant, + Typedef, } pub trait GetDefId { @@ -1567,7 +1569,7 @@ impl PrimitiveType { None } - pub fn to_string(&self) -> &'static str { + pub fn as_str(&self) -> &'static str { match *self { PrimitiveType::Isize => "isize", PrimitiveType::I8 => "i8", @@ -1592,7 +1594,7 @@ impl PrimitiveType { } pub fn to_url_str(&self) -> &'static str { - self.to_string() + self.as_str() } /// Creates a rustdoc-specific node id for primitive types. @@ -1646,8 +1648,8 @@ impl Clean for hir::Ty { TyRptr(ref l, ref m) => BorrowedRef {lifetime: l.clean(cx), mutability: m.mutbl.clean(cx), type_: box m.ty.clean(cx)}, - TyVec(ref ty) => Vector(box ty.clean(cx)), - TyFixedLengthVec(ref ty, ref e) => { + TySlice(ref ty) => Vector(box ty.clean(cx)), + TyArray(ref ty, ref e) => { let n = if let Some(tcx) = cx.tcx_opt() { use rustc_const_math::{ConstInt, ConstUsize}; use rustc_const_eval::eval_const_expr; @@ -1790,9 +1792,9 @@ impl<'tcx> Clean for ty::Ty<'tcx> { ty::TyAdt(def, substs) => { let did = def.did; let kind = match def.adt_kind() { - AdtKind::Struct => TypeStruct, - AdtKind::Union => TypeUnion, - AdtKind::Enum => TypeEnum, + AdtKind::Struct => TypeKind::Struct, + AdtKind::Union => TypeKind::Union, + AdtKind::Enum => TypeKind::Enum, }; inline::record_extern_fqn(cx, did, kind); let path = external_path(cx, &cx.tcx().item_name(did).as_str(), @@ -1806,7 +1808,7 @@ impl<'tcx> Clean for ty::Ty<'tcx> { } ty::TyTrait(ref obj) => { let did = obj.principal.def_id(); - inline::record_extern_fqn(cx, did, TypeTrait); + inline::record_extern_fqn(cx, did, TypeKind::Trait); let mut typarams = vec![]; obj.region_bound.clean(cx).map(|b| typarams.push(RegionBound(b))); @@ -2022,7 +2024,7 @@ impl Clean for doctree::Variant { deprecation: self.depr.clean(cx), def_id: cx.map.local_def_id(self.def.id()), inner: VariantItem(Variant { - kind: struct_def_to_variant_kind(&self.def, cx), + kind: self.def.clean(cx), }), } } @@ -2030,15 +2032,15 @@ impl Clean for doctree::Variant { impl<'tcx> Clean for ty::VariantDefData<'tcx, 'static> { fn clean(&self, cx: &DocContext) -> Item { - let kind = match self.kind { - ty::VariantKind::Unit => CLikeVariant, - ty::VariantKind::Tuple => { - TupleVariant( + let kind = match self.ctor_kind { + CtorKind::Const => VariantKind::CLike, + CtorKind::Fn => { + VariantKind::Tuple( self.fields.iter().map(|f| f.unsubst_ty().clean(cx)).collect() ) } - ty::VariantKind::Struct => { - StructVariant(VariantStruct { + CtorKind::Fictive => { + VariantKind::Struct(VariantStruct { struct_type: doctree::Plain, fields_stripped: false, fields: self.fields.iter().map(|field| { @@ -2071,18 +2073,20 @@ impl<'tcx> Clean for ty::VariantDefData<'tcx, 'static> { #[derive(Clone, RustcEncodable, RustcDecodable, Debug)] pub enum VariantKind { - CLikeVariant, - TupleVariant(Vec), - StructVariant(VariantStruct), + CLike, + Tuple(Vec), + Struct(VariantStruct), } -fn struct_def_to_variant_kind(struct_def: &hir::VariantData, cx: &DocContext) -> VariantKind { - if struct_def.is_struct() { - StructVariant(struct_def.clean(cx)) - } else if struct_def.is_unit() { - CLikeVariant - } else { - TupleVariant(struct_def.fields().iter().map(|x| x.ty.clean(cx)).collect()) +impl Clean for hir::VariantData { + fn clean(&self, cx: &DocContext) -> VariantKind { + if self.is_struct() { + VariantKind::Struct(self.clean(cx)) + } else if self.is_unit() { + VariantKind::CLike + } else { + VariantKind::Tuple(self.fields().iter().map(|x| x.ty.clean(cx)).collect()) + } } } @@ -2521,7 +2525,7 @@ impl Clean> for doctree::Import { }); let (mut ret, inner) = match self.node { hir::ViewPathGlob(ref p) => { - (vec![], GlobImport(resolve_use_source(cx, p.clean(cx), self.id))) + (vec![], Import::Glob(resolve_use_source(cx, p.clean(cx), self.id))) } hir::ViewPathList(ref p, ref list) => { // Attempt to inline all reexported items, but be sure @@ -2547,8 +2551,7 @@ impl Clean> for doctree::Import { if remaining.is_empty() { return ret; } - (ret, ImportList(resolve_use_source(cx, p.clean(cx), self.id), - remaining)) + (ret, Import::List(resolve_use_source(cx, p.clean(cx), self.id), remaining)) } hir::ViewPathSimple(name, ref p) => { if !denied { @@ -2556,8 +2559,8 @@ impl Clean> for doctree::Import { return items; } } - (vec![], SimpleImport(name.clean(cx), - resolve_use_source(cx, p.clean(cx), self.id))) + (vec![], Import::Simple(name.clean(cx), + resolve_use_source(cx, p.clean(cx), self.id))) } }; ret.push(Item { @@ -2577,11 +2580,11 @@ impl Clean> for doctree::Import { #[derive(Clone, RustcEncodable, RustcDecodable, Debug)] pub enum Import { // use source as str; - SimpleImport(String, ImportSource), + Simple(String, ImportSource), // use source::*; - GlobImport(ImportSource), + Glob(ImportSource), // use source::{a, b, c}; - ImportList(ImportSource, Vec), + List(ImportSource, Vec), } #[derive(Clone, RustcEncodable, RustcDecodable, Debug)] @@ -2699,7 +2702,7 @@ fn name_from_pat(p: &hir::Pat) -> String { }, PatKind::Range(..) => panic!("tried to get argument name from PatKind::Range, \ which is not allowed in function arguments"), - PatKind::Vec(ref begin, ref mid, ref end) => { + PatKind::Slice(ref begin, ref mid, ref end) => { let begin = begin.iter().map(|p| name_from_pat(&**p)); let mid = mid.as_ref().map(|p| format!("..{}", name_from_pat(&**p))).into_iter(); let end = end.iter().map(|p| name_from_pat(&**p)); @@ -2756,16 +2759,16 @@ fn register_def(cx: &DocContext, def: Def) -> DefId { let tcx = cx.tcx(); let (did, kind) = match def { - Def::Fn(i) => (i, TypeFunction), - Def::TyAlias(i) => (i, TypeTypedef), - Def::Enum(i) => (i, TypeEnum), - Def::Trait(i) => (i, TypeTrait), - Def::Struct(i) => (i, TypeStruct), - Def::Union(i) => (i, TypeUnion), - Def::Mod(i) => (i, TypeModule), - Def::Static(i, _) => (i, TypeStatic), - Def::Variant(i) => (tcx.parent_def_id(i).unwrap(), TypeEnum), - Def::SelfTy(Some(def_id), _) => (def_id, TypeTrait), + Def::Fn(i) => (i, TypeKind::Function), + Def::TyAlias(i) => (i, TypeKind::Typedef), + Def::Enum(i) => (i, TypeKind::Enum), + Def::Trait(i) => (i, TypeKind::Trait), + Def::Struct(i) => (i, TypeKind::Struct), + Def::Union(i) => (i, TypeKind::Union), + Def::Mod(i) => (i, TypeKind::Module), + Def::Static(i, _) => (i, TypeKind::Static), + Def::Variant(i) => (tcx.parent_def_id(i).unwrap(), TypeKind::Enum), + Def::SelfTy(Some(def_id), _) => (def_id, TypeKind::Trait), Def::SelfTy(_, Some(impl_def_id)) => { return impl_def_id } @@ -2773,7 +2776,7 @@ fn register_def(cx: &DocContext, def: Def) -> DefId { }; if did.is_local() { return did } inline::record_extern_fqn(cx, did, kind); - if let TypeTrait = kind { + if let TypeKind::Trait = kind { let t = inline::build_external_trait(cx, tcx, did); cx.external_traits.borrow_mut().insert(did, t); } @@ -2961,7 +2964,7 @@ fn lang_struct(cx: &DocContext, did: Option, Some(did) => did, None => return fallback(box t.clean(cx)), }; - inline::record_extern_fqn(cx, did, TypeStruct); + inline::record_extern_fqn(cx, did, TypeKind::Struct); ResolvedPath { typarams: None, did: did, diff --git a/src/librustdoc/clean/simplify.rs b/src/librustdoc/clean/simplify.rs index 7ae1774390..15e042f8c0 100644 --- a/src/librustdoc/clean/simplify.rs +++ b/src/librustdoc/clean/simplify.rs @@ -141,7 +141,7 @@ pub fn ty_params(mut params: Vec) -> Vec { for param in &mut params { param.bounds = ty_bounds(mem::replace(&mut param.bounds, Vec::new())); } - return params; + params } fn ty_bounds(bounds: Vec) -> Vec { diff --git a/src/librustdoc/core.rs b/src/librustdoc/core.rs index 49e467e5cb..f03b6a5ab3 100644 --- a/src/librustdoc/core.rs +++ b/src/librustdoc/core.rs @@ -143,13 +143,14 @@ pub fn run_core(search_paths: SearchPaths, let sessopts = config::Options { maybe_sysroot: maybe_sysroot, search_paths: search_paths, - crate_types: vec!(config::CrateTypeRlib), - lint_opts: vec!((warning_lint, lint::Allow)), + crate_types: vec![config::CrateTypeRlib], + lint_opts: vec![(warning_lint, lint::Allow)], lint_cap: Some(lint::Allow), externs: externs, target_triple: triple.unwrap_or(config::host_triple().to_string()), // Ensure that rustdoc works even if rustc is feature-staged unstable_features: UnstableFeatures::Allow, + actually_rustdoc: true, ..config::basic_options().clone() }; @@ -162,14 +163,16 @@ pub fn run_core(search_paths: SearchPaths, let dep_graph = DepGraph::new(false); let _ignore = dep_graph.in_ignore(); let cstore = Rc::new(CStore::new(&dep_graph)); - let sess = session::build_session_(sessopts, &dep_graph, cpath, diagnostic_handler, - codemap, cstore.clone()); + let mut sess = session::build_session_( + sessopts, &dep_graph, cpath, diagnostic_handler, codemap, cstore.clone() + ); rustc_lint::register_builtins(&mut sess.lint_store.borrow_mut(), Some(&sess)); let mut cfg = config::build_configuration(&sess, config::parse_cfgspecs(cfgs)); target_features::add_configuration(&mut cfg, &sess); + sess.parse_sess.config = cfg; - let krate = panictry!(driver::phase_1_parse_input(&sess, cfg, &input)); + let krate = panictry!(driver::phase_1_parse_input(&sess, &input)); let name = link::find_crate_name(Some(&sess), &krate.attrs, &input); @@ -188,7 +191,7 @@ pub fn run_core(search_paths: SearchPaths, resolutions, &arenas, &name, - |tcx, _, analysis, _, result| { + |tcx, analysis, _, result| { if let Err(_) = result { sess.fatal("Compilation failed, aborting rustdoc"); } diff --git a/src/librustdoc/externalfiles.rs b/src/librustdoc/externalfiles.rs index 2ecb071fcc..d78f00497c 100644 --- a/src/librustdoc/externalfiles.rs +++ b/src/librustdoc/externalfiles.rs @@ -11,64 +11,79 @@ use std::fs::File; use std::io::prelude::*; use std::io; -use std::path::{PathBuf, Path}; +use std::path::Path; use std::str; #[derive(Clone)] pub struct ExternalHtml{ + /// Content that will be included inline in the section of a + /// rendered Markdown file or generated documentation pub in_header: String, + /// Content that will be included inline between and the content of + /// a rendered Markdown file or generated documentation pub before_content: String, + /// Content that will be included inline between the content and of + /// a rendered Markdown file or generated documentation pub after_content: String } impl ExternalHtml { pub fn load(in_header: &[String], before_content: &[String], after_content: &[String]) -> Option { - match (load_external_files(in_header), - load_external_files(before_content), - load_external_files(after_content)) { - (Some(ih), Some(bc), Some(ac)) => Some(ExternalHtml { - in_header: ih, - before_content: bc, - after_content: ac - }), - _ => None - } + load_external_files(in_header) + .and_then(|ih| + load_external_files(before_content) + .map(|bc| (ih, bc)) + ) + .and_then(|(ih, bc)| + load_external_files(after_content) + .map(|ac| (ih, bc, ac)) + ) + .map(|(ih, bc, ac)| + ExternalHtml { + in_header: ih, + before_content: bc, + after_content: ac, + } + ) } } -pub fn load_string(input: &Path) -> io::Result> { - let mut f = File::open(input)?; - let mut d = Vec::new(); - f.read_to_end(&mut d)?; - Ok(str::from_utf8(&d).map(|s| s.to_string()).ok()) +pub enum LoadStringError { + ReadFail, + BadUtf8, } -macro_rules! load_or_return { - ($input: expr, $cant_read: expr, $not_utf8: expr) => { - { - let input = PathBuf::from(&$input[..]); - match ::externalfiles::load_string(&input) { - Err(e) => { - let _ = writeln!(&mut io::stderr(), - "error reading `{}`: {}", input.display(), e); - return $cant_read; - } - Ok(None) => { - let _ = writeln!(&mut io::stderr(), - "error reading `{}`: not UTF-8", input.display()); - return $not_utf8; - } - Ok(Some(s)) => s - } +pub fn load_string>(file_path: P) -> Result { + let file_path = file_path.as_ref(); + let mut contents = vec![]; + let result = File::open(file_path) + .and_then(|mut f| f.read_to_end(&mut contents)); + if let Err(e) = result { + let _ = writeln!(&mut io::stderr(), + "error reading `{}`: {}", + file_path.display(), e); + return Err(LoadStringError::ReadFail); + } + match str::from_utf8(&contents) { + Ok(s) => Ok(s.to_string()), + Err(_) => { + let _ = writeln!(&mut io::stderr(), + "error reading `{}`: not UTF-8", + file_path.display()); + Err(LoadStringError::BadUtf8) } } } -pub fn load_external_files(names: &[String]) -> Option { +fn load_external_files(names: &[String]) -> Option { let mut out = String::new(); for name in names { - out.push_str(&*load_or_return!(&name, None, None)); + let s = match load_string(name) { + Ok(s) => s, + Err(_) => return None, + }; + out.push_str(&s); out.push('\n'); } Some(out) diff --git a/src/librustdoc/fold.rs b/src/librustdoc/fold.rs index 8d6ab221c4..e269d940bf 100644 --- a/src/librustdoc/fold.rs +++ b/src/librustdoc/fold.rs @@ -74,12 +74,12 @@ pub trait DocFolder : Sized { VariantItem(i) => { let i2 = i.clone(); // this clone is small match i.kind { - StructVariant(mut j) => { + VariantKind::Struct(mut j) => { let num_fields = j.fields.len(); j.fields = j.fields.into_iter().filter_map(|x| self.fold_item(x)).collect(); j.fields_stripped |= num_fields != j.fields.len() || j.fields.iter().any(|f| f.is_stripped()); - VariantItem(Variant {kind: StructVariant(j), ..i2}) + VariantItem(Variant {kind: VariantKind::Struct(j), ..i2}) }, _ => VariantItem(i2) } diff --git a/src/librustdoc/html/format.rs b/src/librustdoc/html/format.rs index adcdc7aaab..625acce27b 100644 --- a/src/librustdoc/html/format.rs +++ b/src/librustdoc/html/format.rs @@ -42,7 +42,7 @@ pub struct UnsafetySpace(pub hir::Unsafety); #[derive(Copy, Clone)] pub struct ConstnessSpace(pub hir::Constness); /// Wrapper struct for properly emitting a method declaration. -pub struct Method<'a>(pub &'a clean::FnDecl); +pub struct Method<'a>(pub &'a clean::FnDecl, pub &'a str); /// Similar to VisSpace, but used for mutability #[derive(Copy, Clone)] pub struct MutableSpace(pub clean::Mutability); @@ -84,7 +84,7 @@ impl<'a, T: fmt::Display> fmt::Display for CommaSep<'a, T> { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { for (i, item) in self.0.iter().enumerate() { if i != 0 { write!(f, ", ")?; } - write!(f, "{}", item)?; + fmt::Display::fmt(item, f)?; } Ok(()) } @@ -97,7 +97,7 @@ impl<'a> fmt::Display for TyParamBounds<'a> { if i > 0 { f.write_str(" + ")?; } - write!(f, "{}", *bound)?; + fmt::Display::fmt(bound, f)?; } Ok(()) } @@ -106,35 +106,51 @@ 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.is_empty() && self.type_params.is_empty() { return Ok(()) } - f.write_str("<")?; + if f.alternate() { + f.write_str("<")?; + } else { + f.write_str("<")?; + } for (i, life) in self.lifetimes.iter().enumerate() { if i > 0 { - f.write_str(", ")?; + f.write_str(", ")?; } write!(f, "{}", *life)?; } if !self.type_params.is_empty() { if !self.lifetimes.is_empty() { - f.write_str(", ")?; + f.write_str(", ")?; } for (i, tp) in self.type_params.iter().enumerate() { if i > 0 { - f.write_str(", ")? + f.write_str(", ")? } f.write_str(&tp.name)?; if !tp.bounds.is_empty() { - write!(f, ": {}", TyParamBounds(&tp.bounds))?; + if f.alternate() { + write!(f, ": {:#}", TyParamBounds(&tp.bounds))?; + } else { + write!(f, ": {}", TyParamBounds(&tp.bounds))?; + } } if let Some(ref ty) = tp.default { - write!(f, " = {}", ty)?; + if f.alternate() { + write!(f, " = {:#}", ty)?; + } else { + write!(f, " = {}", ty)?; + } }; } } - f.write_str(">")?; + if f.alternate() { + f.write_str(">")?; + } else { + f.write_str(">")?; + } Ok(()) } } @@ -145,7 +161,11 @@ impl<'a> fmt::Display for WhereClause<'a> { if gens.where_predicates.is_empty() { return Ok(()); } - f.write_str(" where ")?; + if f.alternate() { + f.write_str(" ")?; + } else { + f.write_str(" where ")?; + } for (i, pred) in gens.where_predicates.iter().enumerate() { if i > 0 { f.write_str(", ")?; @@ -153,7 +173,11 @@ impl<'a> fmt::Display for WhereClause<'a> { match pred { &clean::WherePredicate::BoundPredicate { ref ty, ref bounds } => { let bounds = bounds; - write!(f, "{}: {}", ty, TyParamBounds(bounds))?; + if f.alternate() { + write!(f, "{:#}: {:#}", ty, TyParamBounds(bounds))?; + } else { + write!(f, "{}: {}", ty, TyParamBounds(bounds))?; + } } &clean::WherePredicate::RegionPredicate { ref lifetime, ref bounds } => { @@ -167,11 +191,17 @@ impl<'a> fmt::Display for WhereClause<'a> { } } &clean::WherePredicate::EqPredicate { ref lhs, ref rhs } => { - write!(f, "{} == {}", lhs, rhs)?; + if f.alternate() { + write!(f, "{:#} == {:#}", lhs, rhs)?; + } else { + write!(f, "{} == {}", lhs, rhs)?; + } } } } - f.write_str("")?; + if !f.alternate() { + f.write_str("")?; + } Ok(()) } } @@ -186,16 +216,28 @@ impl fmt::Display for clean::Lifetime { impl fmt::Display for clean::PolyTrait { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { if !self.lifetimes.is_empty() { - f.write_str("for<")?; + if f.alternate() { + f.write_str("for<")?; + } else { + f.write_str("for<")?; + } for (i, lt) in self.lifetimes.iter().enumerate() { if i > 0 { f.write_str(", ")?; } write!(f, "{}", lt)?; } - f.write_str("> ")?; + if f.alternate() { + f.write_str("> ")?; + } else { + f.write_str("> ")?; + } + } + if f.alternate() { + write!(f, "{:#}", self.trait_) + } else { + write!(f, "{}", self.trait_) } - write!(f, "{}", self.trait_) } } @@ -210,7 +252,11 @@ impl fmt::Display for clean::TyParamBound { hir::TraitBoundModifier::None => "", hir::TraitBoundModifier::Maybe => "?", }; - write!(f, "{}{}", modifier_str, *ty) + if f.alternate() { + write!(f, "{}{:#}", modifier_str, *ty) + } else { + write!(f, "{}{}", modifier_str, *ty) + } } } } @@ -223,30 +269,46 @@ impl fmt::Display for clean::PathParameters { ref lifetimes, ref types, ref bindings } => { if !lifetimes.is_empty() || !types.is_empty() || !bindings.is_empty() { - f.write_str("<")?; + if f.alternate() { + f.write_str("<")?; + } else { + f.write_str("<")?; + } let mut comma = false; for lifetime in lifetimes { if comma { - f.write_str(", ")?; + f.write_str(", ")?; } comma = true; write!(f, "{}", *lifetime)?; } for ty in types { if comma { - f.write_str(", ")?; + f.write_str(", ")?; } comma = true; - write!(f, "{}", *ty)?; + if f.alternate() { + write!(f, "{:#}", *ty)?; + } else { + write!(f, "{}", *ty)?; + } } for binding in bindings { if comma { - f.write_str(", ")?; + f.write_str(", ")?; } comma = true; - write!(f, "{}", *binding)?; + if f.alternate() { + write!(f, "{:#}", *binding)?; + } else { + write!(f, "{}", *binding)?; + } + } + if f.alternate() { + f.write_str(">")?; + } else { + f.write_str(">")?; } - f.write_str(">")?; } } clean::PathParameters::Parenthesized { ref inputs, ref output } => { @@ -257,12 +319,19 @@ impl fmt::Display for clean::PathParameters { f.write_str(", ")?; } comma = true; - write!(f, "{}", *ty)?; + if f.alternate() { + write!(f, "{:#}", *ty)?; + } else { + write!(f, "{}", *ty)?; + } } f.write_str(")")?; if let Some(ref ty) = *output { - f.write_str(" -> ")?; - write!(f, "{}", ty)?; + if f.alternate() { + write!(f, " -> {:#}", ty)?; + } else { + write!(f, " -> {}", ty)?; + } } } } @@ -273,7 +342,11 @@ impl fmt::Display for clean::PathParameters { impl fmt::Display for clean::PathSegment { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { f.write_str(&self.name)?; - write!(f, "{}", self.params) + if f.alternate() { + write!(f, "{:#}", self.params) + } else { + write!(f, "{}", self.params) + } } } @@ -287,7 +360,11 @@ impl fmt::Display for clean::Path { if i > 0 { f.write_str("::")? } - write!(f, "{}", seg)?; + if f.alternate() { + write!(f, "{:#}", seg)?; + } else { + write!(f, "{}", seg)?; + } } Ok(()) } @@ -349,7 +426,7 @@ fn resolved_path(w: &mut fmt::Formatter, did: DefId, path: &clean::Path, match rel_root { Some(mut root) => { for seg in &path.segments[..amt] { - if "super" == seg.name || "self" == seg.name { + if "super" == seg.name || "self" == seg.name || w.alternate() { write!(w, "{}::", seg.name)?; } else { root.push_str(&seg.name); @@ -368,7 +445,11 @@ fn resolved_path(w: &mut fmt::Formatter, did: DefId, path: &clean::Path, } } } - write!(w, "{}{}", HRef::new(did, &last.name), last.params)?; + if w.alternate() { + write!(w, "{:#}{:#}", HRef::new(did, &last.name), last.params)?; + } else { + write!(w, "{}{}", HRef::new(did, &last.name), last.params)?; + } Ok(()) } @@ -377,33 +458,35 @@ fn primitive_link(f: &mut fmt::Formatter, name: &str) -> fmt::Result { let m = cache(); let mut needs_termination = false; - match m.primitive_locations.get(&prim) { - Some(&LOCAL_CRATE) => { - let len = CURRENT_LOCATION_KEY.with(|s| s.borrow().len()); - let len = if len == 0 {0} else {len - 1}; - write!(f, "", - repeat("../").take(len).collect::(), - prim.to_url_str())?; - needs_termination = true; - } - Some(&cnum) => { - let loc = match m.extern_locations[&cnum] { - (ref cname, render::Remote(ref s)) => Some((cname, s.to_string())), - (ref cname, render::Local) => { - let len = CURRENT_LOCATION_KEY.with(|s| s.borrow().len()); - Some((cname, repeat("../").take(len).collect::())) - } - (_, render::Unknown) => None, - }; - if let Some((cname, root)) = loc { - write!(f, "", - root, - cname, + if !f.alternate() { + match m.primitive_locations.get(&prim) { + Some(&LOCAL_CRATE) => { + let len = CURRENT_LOCATION_KEY.with(|s| s.borrow().len()); + let len = if len == 0 {0} else {len - 1}; + write!(f, "", + repeat("../").take(len).collect::(), prim.to_url_str())?; needs_termination = true; } + Some(&cnum) => { + let loc = match m.extern_locations[&cnum] { + (ref cname, render::Remote(ref s)) => Some((cname, s.to_string())), + (ref cname, render::Local) => { + let len = CURRENT_LOCATION_KEY.with(|s| s.borrow().len()); + Some((cname, repeat("../").take(len).collect::())) + } + (_, render::Unknown) => None, + }; + if let Some((cname, root)) = loc { + write!(f, "", + root, + cname, + prim.to_url_str())?; + needs_termination = true; + } + } + None => {} } - None => {} } write!(f, "{}", name)?; if needs_termination { @@ -419,7 +502,7 @@ fn tybounds(w: &mut fmt::Formatter, Some(ref params) => { for param in params { write!(w, " + ")?; - write!(w, "{}", *param)?; + fmt::Display::fmt(param, w)?; } Ok(()) } @@ -436,10 +519,12 @@ impl<'a> HRef<'a> { impl<'a> fmt::Display for HRef<'a> { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { match href(self.did) { - Some((url, shortty, fqp)) => { + Some((url, shortty, fqp)) => if !f.alternate() { write!(f, "{}", shortty, url, fqp.join("::"), self.text) - } + } else { + write!(f, "{}", self.text) + }, _ => write!(f, "{}", self.text), } } @@ -457,51 +542,70 @@ impl fmt::Display for clean::Type { tybounds(f, typarams) } clean::Infer => write!(f, "_"), - clean::Primitive(prim) => primitive_link(f, prim, prim.to_string()), + clean::Primitive(prim) => primitive_link(f, prim, prim.as_str()), clean::BareFunction(ref decl) => { - write!(f, "{}{}fn{}{}", - UnsafetySpace(decl.unsafety), - AbiSpace(decl.abi), - decl.generics, - decl.decl) + if f.alternate() { + write!(f, "{}{}fn{:#}{:#}", + UnsafetySpace(decl.unsafety), + AbiSpace(decl.abi), + decl.generics, + decl.decl) + } else { + write!(f, "{}{}fn{}{}", + UnsafetySpace(decl.unsafety), + AbiSpace(decl.abi), + decl.generics, + decl.decl) + } } clean::Tuple(ref typs) => { match &typs[..] { &[] => primitive_link(f, PrimitiveType::Tuple, "()"), &[ref one] => { primitive_link(f, PrimitiveType::Tuple, "(")?; - write!(f, "{},", one)?; - primitive_link(f, PrimitiveType::Tuple, ")") + //carry f.alternate() into this display w/o branching manually + fmt::Display::fmt(one, f)?; + primitive_link(f, PrimitiveType::Tuple, ",)") } many => { primitive_link(f, PrimitiveType::Tuple, "(")?; - write!(f, "{}", CommaSep(&many))?; + fmt::Display::fmt(&CommaSep(&many), f)?; primitive_link(f, PrimitiveType::Tuple, ")") } } } clean::Vector(ref t) => { primitive_link(f, PrimitiveType::Slice, &format!("["))?; - write!(f, "{}", t)?; + fmt::Display::fmt(t, f)?; primitive_link(f, PrimitiveType::Slice, &format!("]")) } clean::FixedVector(ref t, ref s) => { primitive_link(f, PrimitiveType::Array, "[")?; - write!(f, "{}", t)?; - primitive_link(f, PrimitiveType::Array, - &format!("; {}]", Escape(s))) + fmt::Display::fmt(t, f)?; + if f.alternate() { + primitive_link(f, PrimitiveType::Array, + &format!("; {}]", s)) + } else { + primitive_link(f, PrimitiveType::Array, + &format!("; {}]", Escape(s))) + } } clean::Never => f.write_str("!"), clean::RawPointer(m, ref t) => { match **t { clean::Generic(_) | clean::ResolvedPath {is_generic: true, ..} => { - primitive_link(f, clean::PrimitiveType::RawPointer, - &format!("*{}{}", RawMutableSpace(m), t)) + if f.alternate() { + primitive_link(f, clean::PrimitiveType::RawPointer, + &format!("*{}{:#}", RawMutableSpace(m), t)) + } else { + primitive_link(f, clean::PrimitiveType::RawPointer, + &format!("*{}{}", RawMutableSpace(m), t)) + } } _ => { primitive_link(f, clean::PrimitiveType::RawPointer, &format!("*{}", RawMutableSpace(m)))?; - write!(f, "{}", t) + fmt::Display::fmt(t, f) } } } @@ -515,18 +619,33 @@ impl fmt::Display for clean::Type { clean::Vector(ref bt) => { // BorrowedRef{ ... Vector(T) } is &[T] match **bt { clean::Generic(_) => - primitive_link(f, PrimitiveType::Slice, - &format!("&{}{}[{}]", lt, m, **bt)), + if f.alternate() { + primitive_link(f, PrimitiveType::Slice, + &format!("&{}{}[{:#}]", lt, m, **bt)) + } else { + primitive_link(f, PrimitiveType::Slice, + &format!("&{}{}[{}]", lt, m, **bt)) + }, _ => { - primitive_link(f, PrimitiveType::Slice, - &format!("&{}{}[", lt, m))?; - write!(f, "{}", **bt)?; + if f.alternate() { + primitive_link(f, PrimitiveType::Slice, + &format!("&{}{}[", lt, m))?; + write!(f, "{:#}", **bt)?; + } else { + primitive_link(f, PrimitiveType::Slice, + &format!("&{}{}[", lt, m))?; + write!(f, "{}", **bt)?; + } primitive_link(f, PrimitiveType::Slice, "]") } } } _ => { - write!(f, "&{}{}{}", lt, m, **ty) + if f.alternate() { + write!(f, "&{}{}{:#}", lt, m, **ty) + } else { + write!(f, "&{}{}{}", lt, m, **ty) + } } } } @@ -535,7 +654,11 @@ impl fmt::Display for clean::Type { if i != 0 { write!(f, " + ")?; } - write!(f, "{}", *bound)?; + if f.alternate() { + write!(f, "{:#}", *bound)?; + } else { + write!(f, "{}", *bound)?; + } } Ok(()) } @@ -545,7 +668,11 @@ impl fmt::Display for clean::Type { if i != 0 { write!(f, " + ")?; } - write!(f, "{}", *bound)?; + if f.alternate() { + write!(f, "{:#}", *bound)?; + } else { + write!(f, "{}", *bound)?; + } } Ok(()) } @@ -564,7 +691,11 @@ impl fmt::Display for clean::Type { ref self_type, trait_: box clean::ResolvedPath { did, ref typarams, .. }, } => { - write!(f, "{}::", self_type)?; + if f.alternate() { + write!(f, "{:#}::", self_type)?; + } else { + write!(f, "{}::", self_type)?; + } let path = clean::Path::singleton(name.clone()); resolved_path(f, did, &path, false)?; @@ -573,7 +704,11 @@ impl fmt::Display for clean::Type { Ok(()) } clean::QPath { ref name, ref self_type, ref trait_ } => { - write!(f, "<{} as {}>::{}", self_type, trait_, name) + if f.alternate() { + write!(f, "<{:#} as {:#}>::{}", self_type, trait_, name) + } else { + write!(f, "<{} as {}>::{}", self_type, trait_, name) + } } clean::Unique(..) => { panic!("should have been cleaned") @@ -583,24 +718,30 @@ impl fmt::Display for clean::Type { } fn fmt_impl(i: &clean::Impl, f: &mut fmt::Formatter, link_trait: bool) -> fmt::Result { - write!(f, "impl{} ", i.generics)?; + if f.alternate() { + write!(f, "impl{:#} ", i.generics)?; + } else { + write!(f, "impl{} ", i.generics)?; + } if let Some(ref ty) = i.trait_ { write!(f, "{}", if i.polarity == Some(clean::ImplPolarity::Negative) { "!" } else { "" })?; if link_trait { - write!(f, "{}", *ty)?; + fmt::Display::fmt(ty, f)?; } else { match *ty { clean::ResolvedPath{ typarams: None, ref path, is_generic: false, .. } => { let last = path.segments.last().unwrap(); - write!(f, "{}{}", last.name, last.params)?; + fmt::Display::fmt(&last.name, f)?; + fmt::Display::fmt(&last.params, f)?; } _ => unreachable!(), } } write!(f, " for ")?; } - write!(f, "{}{}", i.for_, WhereClause(&i.generics))?; + fmt::Display::fmt(&i.for_, f)?; + fmt::Display::fmt(&WhereClause(&i.generics), f)?; Ok(()) } @@ -618,11 +759,15 @@ pub fn fmt_impl_for_trait_page(i: &clean::Impl, f: &mut fmt::Formatter) -> fmt:: 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 { write!(f, ", ")?; } if !input.name.is_empty() { write!(f, "{}: ", input.name)?; } - write!(f, "{}", input.type_)?; + if f.alternate() { + write!(f, "{:#}", input.type_)?; + } else { + write!(f, "{}", input.type_)?; + } + if i + 1 < self.values.len() { write!(f, ", ")?; } } Ok(()) } @@ -632,6 +777,7 @@ impl fmt::Display for clean::FunctionRetTy { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { match *self { clean::Return(clean::Tuple(ref tys)) if tys.is_empty() => Ok(()), + clean::Return(ref ty) if f.alternate() => write!(f, " -> {:#}", ty), clean::Return(ref ty) => write!(f, " -> {}", ty), clean::DefaultReturn => Ok(()), } @@ -641,9 +787,17 @@ impl fmt::Display for clean::FunctionRetTy { impl fmt::Display for clean::FnDecl { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { if self.variadic { - write!(f, "({args}, ...){arrow}", args = self.inputs, arrow = self.output) + if f.alternate() { + write!(f, "({args:#}, ...){arrow:#}", args = self.inputs, arrow = self.output) + } else { + write!(f, "({args}, ...){arrow}", args = self.inputs, arrow = self.output) + } } else { - write!(f, "({args}){arrow}", args = self.inputs, arrow = self.output) + if f.alternate() { + write!(f, "({args:#}){arrow:#}", args = self.inputs, arrow = self.output) + } else { + write!(f, "({args}){arrow}", args = self.inputs, arrow = self.output) + } } } } @@ -651,30 +805,89 @@ impl fmt::Display for clean::FnDecl { impl<'a> fmt::Display for Method<'a> { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { let decl = self.0; + let indent = self.1; + let amp = if f.alternate() { "&" } else { "&" }; let mut args = String::new(); + let mut args_plain = String::new(); for (i, input) in decl.inputs.values.iter().enumerate() { - if i > 0 || !args.is_empty() { args.push_str(", "); } if let Some(selfty) = input.to_self() { match selfty { - clean::SelfValue => args.push_str("self"), + clean::SelfValue => { + args.push_str("self"); + args_plain.push_str("self"); + } clean::SelfBorrowed(Some(ref lt), mtbl) => { - args.push_str(&format!("&{} {}self", *lt, MutableSpace(mtbl))); + args.push_str(&format!("{}{} {}self", amp, *lt, MutableSpace(mtbl))); + args_plain.push_str(&format!("&{} {}self", *lt, MutableSpace(mtbl))); } clean::SelfBorrowed(None, mtbl) => { - args.push_str(&format!("&{}self", MutableSpace(mtbl))); + args.push_str(&format!("{}{}self", amp, MutableSpace(mtbl))); + args_plain.push_str(&format!("&{}self", MutableSpace(mtbl))); } clean::SelfExplicit(ref typ) => { - args.push_str(&format!("self: {}", *typ)); + if f.alternate() { + args.push_str(&format!("self: {:#}", *typ)); + } else { + args.push_str(&format!("self: {}", *typ)); + } + args_plain.push_str(&format!("self: {:#}", *typ)); } } } else { + if i > 0 { + args.push_str("
"); + args_plain.push_str(" "); + } if !input.name.is_empty() { args.push_str(&format!("{}: ", input.name)); + args_plain.push_str(&format!("{}: ", input.name)); } - args.push_str(&format!("{}", input.type_)); + + if f.alternate() { + args.push_str(&format!("{:#}", input.type_)); + } else { + args.push_str(&format!("{}", input.type_)); + } + args_plain.push_str(&format!("{:#}", input.type_)); + } + if i + 1 < decl.inputs.values.len() { + args.push_str(","); + args_plain.push_str(","); } } - write!(f, "({args}){arrow}", args = args, arrow = decl.output) + + if decl.variadic { + args.push_str(",
..."); + args_plain.push_str(", ..."); + } + + let arrow_plain = format!("{:#}", decl.output); + let arrow = if f.alternate() { + format!("{:#}", decl.output) + } else { + format!("{}", decl.output) + }; + + let mut output: String; + let plain: String; + if arrow.is_empty() { + output = format!("({})", args); + plain = format!("{}({})", indent.replace(" ", " "), args_plain); + } else { + output = format!("({args})
{arrow}", args = args, arrow = arrow); + plain = format!("{indent}({args}){arrow}", + indent = indent.replace(" ", " "), + args = args_plain, + arrow = arrow_plain); + } + + if plain.len() > 80 { + let pad = format!("
{}", indent); + output = output.replace("
", &pad); + } else { + output = output.replace("
", ""); + } + write!(f, "{}", output) } } @@ -708,17 +921,17 @@ impl fmt::Display for ConstnessSpace { impl fmt::Display for clean::Import { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { match *self { - clean::SimpleImport(ref name, ref src) => { + clean::Import::Simple(ref name, ref src) => { if *name == src.path.last_name() { write!(f, "use {};", *src) } else { write!(f, "use {} as {};", *src, *name) } } - clean::GlobImport(ref src) => { + clean::Import::Glob(ref src) => { write!(f, "use {}::*;", *src) } - clean::ImportList(ref src, ref names) => { + clean::Import::List(ref src, ref names) => { write!(f, "use {}::{{", *src)?; for (i, n) in names.iter().enumerate() { if i > 0 { @@ -768,7 +981,11 @@ impl fmt::Display for clean::ViewListIdent { impl fmt::Display for clean::TypeBinding { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - write!(f, "{}={}", self.name, self.ty) + if f.alternate() { + write!(f, "{}={:#}", self.name, self.ty) + } else { + write!(f, "{}={}", self.name, self.ty) + } } } @@ -792,10 +1009,11 @@ impl fmt::Display for RawMutableSpace { impl fmt::Display for AbiSpace { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + let quot = if f.alternate() { "\"" } else { """ }; match self.0 { Abi::Rust => Ok(()), Abi::C => write!(f, "extern "), - abi => write!(f, "extern "{}" ", abi.name()), + abi => write!(f, "extern {0}{1}{0} ", quot, abi.name()), } } } diff --git a/src/librustdoc/html/highlight.rs b/src/librustdoc/html/highlight.rs index 881352cb73..bd47b1e7c1 100644 --- a/src/librustdoc/html/highlight.rs +++ b/src/librustdoc/html/highlight.rs @@ -104,6 +104,7 @@ pub enum Class { Lifetime, PreludeTy, PreludeVal, + QuestionMark, } /// Trait that controls writing the output of syntax highlighting. Users should @@ -237,8 +238,10 @@ impl<'a> Classifier<'a> { token::Dot | token::DotDot | token::DotDotDot | token::Comma | token::Semi | token::Colon | token::ModSep | token::LArrow | token::OpenDelim(_) | token::CloseDelim(token::Brace) | token::CloseDelim(token::Paren) | - token::CloseDelim(token::NoDelim) | - token::Question => Class::None, + token::CloseDelim(token::NoDelim) => Class::None, + + token::Question => Class::QuestionMark, + token::Dollar => { if self.lexer.peek().tok.is_ident() { self.in_macro_nonterminal = true; @@ -292,7 +295,9 @@ impl<'a> Classifier<'a> { "Option" | "Result" => Class::PreludeTy, "Some" | "None" | "Ok" | "Err" => Class::PreludeVal, + "$crate" => Class::KeyWord, _ if tas.tok.is_any_keyword() => Class::KeyWord, + _ => { if self.in_macro_nonterminal { self.in_macro_nonterminal = false; @@ -307,9 +312,6 @@ impl<'a> Classifier<'a> { } } - // Special macro vars are like keywords. - token::SpecialVarNt(_) => Class::KeyWord, - token::Lifetime(..) => Class::Lifetime, token::Underscore | token::Eof | token::Interpolated(..) | @@ -348,6 +350,7 @@ impl Class { Class::Lifetime => "lifetime", Class::PreludeTy => "prelude-ty", Class::PreludeVal => "prelude-val", + Class::QuestionMark => "question-mark" } } } diff --git a/src/librustdoc/html/item_type.rs b/src/librustdoc/html/item_type.rs index b93dc17dbd..f584c4e2f4 100644 --- a/src/librustdoc/html/item_type.rs +++ b/src/librustdoc/html/item_type.rs @@ -90,16 +90,16 @@ impl<'a> From<&'a clean::Item> for ItemType { impl From for ItemType { fn from(kind: clean::TypeKind) -> ItemType { match kind { - clean::TypeStruct => ItemType::Struct, - clean::TypeUnion => ItemType::Union, - clean::TypeEnum => ItemType::Enum, - clean::TypeFunction => ItemType::Function, - clean::TypeTrait => ItemType::Trait, - clean::TypeModule => ItemType::Module, - clean::TypeStatic => ItemType::Static, - clean::TypeConst => ItemType::Constant, - clean::TypeVariant => ItemType::Variant, - clean::TypeTypedef => ItemType::Typedef, + clean::TypeKind::Struct => ItemType::Struct, + clean::TypeKind::Union => ItemType::Union, + clean::TypeKind::Enum => ItemType::Enum, + clean::TypeKind::Function => ItemType::Function, + clean::TypeKind::Trait => ItemType::Trait, + clean::TypeKind::Module => ItemType::Module, + clean::TypeKind::Static => ItemType::Static, + clean::TypeKind::Const => ItemType::Constant, + clean::TypeKind::Variant => ItemType::Variant, + clean::TypeKind::Typedef => ItemType::Typedef, } } } diff --git a/src/librustdoc/html/layout.rs b/src/librustdoc/html/layout.rs index 151e138efe..5353642e29 100644 --- a/src/librustdoc/html/layout.rs +++ b/src/librustdoc/html/layout.rs @@ -19,7 +19,6 @@ pub struct Layout { pub favicon: String, pub external_html: ExternalHtml, pub krate: String, - pub playground_url: String, } pub struct Page<'a> { @@ -136,11 +135,9 @@ r##" - {play_js} "##, @@ -174,12 +171,6 @@ r##" after_content = layout.external_html.after_content, sidebar = *sidebar, krate = layout.krate, - play_url = layout.playground_url, - 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 e9a1f650c9..67cf12f4f4 100644 --- a/src/librustdoc/html/markdown.rs +++ b/src/librustdoc/html/markdown.rs @@ -31,7 +31,7 @@ use std::ascii::AsciiExt; use std::cell::RefCell; use std::default::Default; use std::ffi::CString; -use std::fmt; +use std::fmt::{self, Write}; use std::slice; use std::str; use syntax::feature_gate::UnstableFeatures; @@ -214,7 +214,9 @@ fn collapse_whitespace(s: &str) -> String { s.split_whitespace().collect::>().join(" ") } -thread_local!(pub static PLAYGROUND_KRATE: RefCell>> = { +// Information about the playground if a URL has been specified, containing an +// optional crate name and the URL. +thread_local!(pub static PLAYGROUND: RefCell, String)>> = { RefCell::new(None) }); @@ -248,24 +250,53 @@ pub fn render(w: &mut fmt::Formatter, s: &str, print_toc: bool) -> fmt::Result { }); let text = lines.collect::>().join("\n"); if rendered { return } - PLAYGROUND_KRATE.with(|krate| { + PLAYGROUND.with(|play| { // insert newline to clearly separate it from the // previous block so we can shorten the html output let mut s = String::from("\n"); - krate.borrow().as_ref().map(|krate| { + let playground_button = play.borrow().as_ref().and_then(|&(ref krate, ref url)| { + if url.is_empty() { + return None; + } let test = origtext.lines().map(|l| { stripped_filtered_line(l).unwrap_or(l) }).collect::>().join("\n"); let krate = krate.as_ref().map(|s| &**s); let test = test::maketest(&test, krate, false, &Default::default()); - s.push_str(&format!("{}", Escape(&test))); + let channel = if test.contains("#![feature(") { + "&version=nightly" + } else { + "" + }; + // These characters don't need to be escaped in a URI. + // FIXME: use a library function for percent encoding. + fn dont_escape(c: u8) -> bool { + (b'a' <= c && c <= b'z') || + (b'A' <= c && c <= b'Z') || + (b'0' <= c && c <= b'9') || + c == b'-' || c == b'_' || c == b'.' || + c == b'~' || c == b'!' || c == b'\'' || + c == b'(' || c == b')' || c == b'*' + } + let mut test_escaped = String::new(); + for b in test.bytes() { + if dont_escape(b) { + test_escaped.push(char::from(b)); + } else { + write!(test_escaped, "%{:02X}", b).unwrap(); + } + } + Some(format!( + r#"Run"#, + url, test_escaped, channel + )) }); s.push_str(&highlight::render_with_highlighting( &text, Some("rust-example-rendered"), None, - Some("Run"))); + playground_button.as_ref().map(String::as_str))); let output = CString::new(s).unwrap(); hoedown_buffer_puts(ob, output.as_ptr()); }) @@ -613,7 +644,7 @@ mod tests { t("test_harness", false, false, false, true, true, false, Vec::new()); t("compile_fail", false, true, false, true, false, true, Vec::new()); t("E0450", false, false, false, true, false, false, - vec!("E0450".to_owned())); + vec!["E0450".to_owned()]); t("{.no_run .example}", false, true, false, true, false, false, Vec::new()); t("{.sh .should_panic}", true, false, false, true, false, false, Vec::new()); t("{.example .rust}", false, false, false, true, false, false, Vec::new()); diff --git a/src/librustdoc/html/render.rs b/src/librustdoc/html/render.rs index 9c80f6e98c..a848a011f8 100644 --- a/src/librustdoc/html/render.rs +++ b/src/librustdoc/html/render.rs @@ -89,9 +89,6 @@ pub struct Context { /// Current hierarchy of components leading down to what's currently being /// rendered pub current: Vec, - /// String representation of how to get back to the root path of the 'doc/' - /// folder in terms of a relative URL. - pub root_path: String, /// The current destination folder of where HTML artifacts should be placed. /// This changes as the context descends into the module hierarchy. pub dst: PathBuf, @@ -452,7 +449,6 @@ pub fn run(mut krate: clean::Crate, favicon: "".to_string(), external_html: external_html.clone(), krate: krate.name.clone(), - playground_url: "".to_string(), }, css_file_extension: css_file_extension.clone(), }; @@ -472,11 +468,10 @@ pub fn run(mut krate: clean::Crate, } clean::NameValue(ref x, ref s) if "html_playground_url" == *x => { - scx.layout.playground_url = s.to_string(); - markdown::PLAYGROUND_KRATE.with(|slot| { + markdown::PLAYGROUND.with(|slot| { if slot.borrow().is_none() { let name = krate.name.clone(); - *slot.borrow_mut() = Some(Some(name)); + *slot.borrow_mut() = Some((Some(name), s.clone())); } }); } @@ -496,7 +491,6 @@ pub fn run(mut krate: clean::Crate, krate = render_sources(&dst, &mut scx, krate)?; let cx = Context { current: Vec::new(), - root_path: String::new(), dst: dst, render_redirect_pages: false, shared: Arc::new(scx), @@ -591,7 +585,7 @@ fn build_index(krate: &clean::Crate, cache: &mut Cache) -> String { for &(did, ref item) in orphan_impl_items { if let Some(&(ref fqp, _)) = paths.get(&did) { search_index.push(IndexItem { - ty: item_type(item), + ty: item.type_(), name: item.name.clone().unwrap(), path: fqp[..fqp.len() - 1].join("::"), desc: Escape(&shorter(item.doc_value())).to_string(), @@ -663,8 +657,6 @@ fn write_shared(cx: &Context, include_bytes!("static/jquery-2.1.4.min.js"))?; write(cx.dst.join("main.js"), include_bytes!("static/main.js"))?; - write(cx.dst.join("playpen.js"), - include_bytes!("static/playpen.js"))?; write(cx.dst.join("rustdoc.css"), include_bytes!("static/rustdoc.css"))?; write(cx.dst.join("main.css"), @@ -726,7 +718,7 @@ fn write_shared(cx: &Context, ret.push(line.to_string()); } } - return Ok(ret); + Ok(ret) } // Update the search index @@ -835,11 +827,6 @@ fn mkdir(path: &Path) -> io::Result<()> { } } -/// Returns a documentation-level item type from the item. -fn item_type(item: &clean::Item) -> ItemType { - ItemType::from(item) -} - /// Takes a path to a source file and cleans the path to it. This canonicalizes /// things like ".." to components which preserve the "top down" hierarchy of a /// static HTML tree. Each component in the cleaned path will be passed as an @@ -1075,7 +1062,7 @@ impl DocFolder for Cache { // inserted later on when serializing the search-index. if item.def_id.index != CRATE_DEF_INDEX { self.search_index.push(IndexItem { - ty: item_type(&item), + ty: item.type_(), name: s.to_string(), path: path.join("::").to_string(), desc: Escape(&shorter(item.doc_value())).to_string(), @@ -1122,7 +1109,7 @@ impl DocFolder for Cache { self.access_levels.is_public(item.def_id) { self.paths.insert(item.def_id, - (self.stack.clone(), item_type(&item))); + (self.stack.clone(), item.type_())); } } // link variants to their parent enum because pages aren't emitted @@ -1135,7 +1122,7 @@ impl DocFolder for Cache { clean::PrimitiveItem(..) if item.visibility.is_some() => { self.paths.insert(item.def_id, (self.stack.clone(), - item_type(&item))); + item.type_())); } _ => {} @@ -1217,7 +1204,7 @@ impl DocFolder for Cache { self.seen_mod = orig_seen_mod; self.stripped_mod = orig_stripped_mod; self.parent_is_trait_impl = orig_parent_is_trait_impl; - return ret; + ret } } @@ -1230,6 +1217,12 @@ impl<'a> Cache { } impl Context { + /// String representation of how to get back to the root path of the 'doc/' + /// folder in terms of a relative URL. + fn root_path(&self) -> String { + repeat("../").take(self.current.len()).collect::() + } + /// Recurse in the directory structure and change the "root path" to make /// sure it always points to the top (relatively) fn recurse(&mut self, s: String, f: F) -> T where @@ -1240,7 +1233,6 @@ impl Context { } let prev = self.dst.clone(); self.dst.push(&s); - self.root_path.push_str("../"); self.current.push(s); info!("Recursing into {}", self.dst.display()); @@ -1251,11 +1243,9 @@ impl Context { // Go back to where we were at self.dst = prev; - let len = self.root_path.len(); - self.root_path.truncate(len - 3); self.current.pop().unwrap(); - return ret; + ret } /// Main method for rendering a crate. @@ -1270,7 +1260,7 @@ impl Context { item.name = Some(krate.name); // render the crate documentation - let mut work = vec!((self, item)); + let mut work = vec![(self, item)]; while let Some((mut cx, item)) = work.pop() { cx.item(item, |cx, item| { @@ -1304,7 +1294,7 @@ impl Context { title.push_str(it.name.as_ref().unwrap()); } title.push_str(" - Rust"); - let tyname = item_type(it).css_class(); + let tyname = it.type_().css_class(); let desc = if it.is_crate() { format!("API documentation for the Rust `{}` crate.", self.shared.layout.krate) @@ -1315,7 +1305,7 @@ impl Context { let keywords = make_item_keywords(it); let page = layout::Page { css_class: tyname, - root_path: &self.root_path, + root_path: &self.root_path(), title: &title, description: &desc, keywords: &keywords, @@ -1329,8 +1319,7 @@ impl Context { &Item{ cx: self, item: it }, self.shared.css_file_extension.is_some())?; } else { - let mut url = repeat("../").take(self.current.len()) - .collect::(); + let mut url = self.root_path(); if let Some(&(ref names, ty)) = cache().paths.get(&it.def_id) { for name in &names[..names.len() - 1] { url.push_str(name); @@ -1407,7 +1396,7 @@ impl Context { // buf will be empty if the item is stripped and there is no redirect for it if !buf.is_empty() { let name = item.name.as_ref().unwrap(); - let item_type = item_type(&item); + let item_type = item.type_(); let file_name = &item_path(item_type, name); let joint_dst = self.dst.join(file_name); try_err!(fs::create_dir_all(&self.dst), &self.dst); @@ -1444,7 +1433,7 @@ impl Context { for item in &m.items { if maybe_ignore_item(item) { continue } - let short = item_type(item).css_class(); + let short = item.type_().css_class(); let myname = match item.name { None => continue, Some(ref s) => s.to_string(), @@ -1457,7 +1446,7 @@ impl Context { for (_, items) in &mut map { items.sort(); } - return map; + map } } @@ -1492,7 +1481,7 @@ impl<'a> Item<'a> { }).map(|l| &l.1); let root = match root { Some(&Remote(ref s)) => s.to_string(), - Some(&Local) => self.cx.root_path.clone(), + Some(&Local) => self.cx.root_path(), None | Some(&Unknown) => return None, }; Some(format!("{root}/{krate}/macro.{name}.html?gotomacrosrc=1", @@ -1507,7 +1496,7 @@ impl<'a> Item<'a> { let path = PathBuf::from(&self.item.source.filename); self.cx.shared.local_sources.get(&path).map(|path| { format!("{root}src/{krate}/{path}#{href}", - root = self.cx.root_path, + root = self.cx.root_path(), krate = self.cx.shared.layout.krate, path = path, href = href) @@ -1531,7 +1520,7 @@ impl<'a> Item<'a> { }; let mut path = match cache.extern_locations.get(&self.item.def_id.krate) { Some(&(_, Remote(ref s))) => s.to_string(), - Some(&(_, Local)) => self.cx.root_path.clone(), + Some(&(_, Local)) => self.cx.root_path(), Some(&(_, Unknown)) => return None, None => return None, }; @@ -1541,7 +1530,7 @@ impl<'a> Item<'a> { } Some(format!("{path}{file}?gotosrc={goto}", path = path, - file = item_path(item_type(self.item), external_path.last().unwrap()), + file = item_path(self.item.type_(), external_path.last().unwrap()), goto = self.item.def_id.index.as_usize())) } } @@ -1586,7 +1575,7 @@ impl<'a> fmt::Display for Item<'a> { } } write!(fmt, "{}", - item_type(self.item), self.item.name.as_ref().unwrap())?; + self.item.type_(), self.item.name.as_ref().unwrap())?; write!(fmt, "")?; // in-band write!(fmt, "")?; @@ -1654,7 +1643,7 @@ fn full_path(cx: &Context, item: &clean::Item) -> String { let mut s = cx.current.join("::"); s.push_str("::"); s.push_str(item.name.as_ref().unwrap()); - return s + s } fn shorter<'a>(s: Option<&'a str>) -> String { @@ -1739,8 +1728,8 @@ fn item_module(w: &mut fmt::Formatter, cx: &Context, } fn cmp(i1: &clean::Item, i2: &clean::Item, idx1: usize, idx2: usize) -> Ordering { - let ty1 = item_type(i1); - let ty2 = item_type(i2); + let ty1 = i1.type_(); + let ty2 = i2.type_(); if ty1 != ty2 { return (reorder(ty1), idx1).cmp(&(reorder(ty2), idx2)) } @@ -1764,7 +1753,7 @@ fn item_module(w: &mut fmt::Formatter, cx: &Context, continue; } - let myty = Some(item_type(myitem)); + let myty = Some(myitem.type_()); if curty == Some(ItemType::ExternCrate) && myty == Some(ItemType::Import) { // Put `extern crate` and `use` re-exports in the same section. curty = myty; @@ -1851,9 +1840,9 @@ fn item_module(w: &mut fmt::Formatter, cx: &Context, name = *myitem.name.as_ref().unwrap(), stab_docs = stab_docs, docs = shorter(Some(&Markdown(doc_value).to_string())), - class = item_type(myitem), + class = myitem.type_(), stab = myitem.stability_class(), - href = item_path(item_type(myitem), myitem.name.as_ref().unwrap()), + href = item_path(myitem.type_(), myitem.name.as_ref().unwrap()), title = full_path(cx, myitem))?; } } @@ -1974,6 +1963,14 @@ fn item_function(w: &mut fmt::Formatter, cx: &Context, it: &clean::Item, UnstableFeatures::Allow => f.constness, _ => hir::Constness::NotConst }; + let prefix = format!("{}{}{}{:#}fn {}{:#}", + VisSpace(&it.visibility), + ConstnessSpace(vis_constness), + UnsafetySpace(f.unsafety), + AbiSpace(f.abi), + it.name.as_ref().unwrap(), + f.generics); + let indent = repeat(" ").take(prefix.len()).collect::(); write!(w, "
{vis}{constness}{unsafety}{abi}fn \
                {name}{generics}{decl}{where_clause}
", vis = VisSpace(&it.visibility), @@ -1983,7 +1980,7 @@ fn item_function(w: &mut fmt::Formatter, cx: &Context, it: &clean::Item, name = it.name.as_ref().unwrap(), generics = f.generics, where_clause = WhereClause(&f.generics), - decl = f.decl)?; + decl = Method(&f.decl, &indent))?; document(w, cx, it) } @@ -2059,7 +2056,7 @@ fn item_trait(w: &mut fmt::Formatter, cx: &Context, it: &clean::Item, fn trait_item(w: &mut fmt::Formatter, cx: &Context, m: &clean::Item, t: &clean::Item) -> fmt::Result { let name = m.name.as_ref().unwrap(); - let item_type = item_type(m); + let item_type = m.type_(); let id = derive_id(format!("{}.{}", item_type, name)); let ns_id = derive_id(format!("{}.{}", name, item_type.name_space())); write!(w, "

\ @@ -2145,7 +2142,7 @@ fn item_trait(w: &mut fmt::Formatter, cx: &Context, it: &clean::Item, let (ref path, _) = cache.external_paths[&it.def_id]; path[..path.len() - 1].join("/") }, - ty = item_type(it).css_class(), + ty = it.type_().css_class(), name = *it.name.as_ref().unwrap())?; Ok(()) } @@ -2154,7 +2151,7 @@ fn naive_assoc_href(it: &clean::Item, link: AssocItemLink) -> String { use html::item_type::ItemType::*; let name = it.name.as_ref().unwrap(); - let ty = match item_type(it) { + let ty = match it.type_() { Typedef | AssociatedType => AssociatedType, s@_ => s, }; @@ -2232,7 +2229,7 @@ fn render_assoc_item(w: &mut fmt::Formatter, link: AssocItemLink) -> fmt::Result { let name = meth.name.as_ref().unwrap(); - let anchor = format!("#{}.{}", item_type(meth), name); + let anchor = format!("#{}.{}", meth.type_(), name); let href = match link { AssocItemLink::Anchor(Some(ref id)) => format!("#{}", id), AssocItemLink::Anchor(None) => anchor, @@ -2253,6 +2250,13 @@ fn render_assoc_item(w: &mut fmt::Formatter, UnstableFeatures::Allow => constness, _ => hir::Constness::NotConst }; + let prefix = format!("{}{}{:#}fn {}{:#}", + ConstnessSpace(vis_constness), + UnsafetySpace(unsafety), + AbiSpace(abi), + name, + *g); + let indent = repeat(" ").take(prefix.len()).collect::(); write!(w, "{}{}{}fn {name}\ {generics}{decl}{where_clause}", ConstnessSpace(vis_constness), @@ -2261,7 +2265,7 @@ fn render_assoc_item(w: &mut fmt::Formatter, href = href, name = name, generics = *g, - decl = Method(d), + decl = Method(d, &indent), where_clause = WhereClause(g)) } match item.inner { @@ -2385,8 +2389,8 @@ fn item_enum(w: &mut fmt::Formatter, cx: &Context, it: &clean::Item, match v.inner { clean::VariantItem(ref var) => { match var.kind { - clean::CLikeVariant => write!(w, "{}", name)?, - clean::TupleVariant(ref tys) => { + clean::VariantKind::CLike => write!(w, "{}", name)?, + clean::VariantKind::Tuple(ref tys) => { write!(w, "{}(", name)?; for (i, ty) in tys.iter().enumerate() { if i > 0 { @@ -2396,7 +2400,7 @@ fn item_enum(w: &mut fmt::Formatter, cx: &Context, it: &clean::Item, } write!(w, ")")?; } - clean::StructVariant(ref s) => { + clean::VariantKind::Struct(ref s) => { render_struct(w, v, None, @@ -2436,7 +2440,7 @@ fn item_enum(w: &mut fmt::Formatter, cx: &Context, it: &clean::Item, ns_id = ns_id, name = variant.name.as_ref().unwrap())?; if let clean::VariantItem(ref var) = variant.inner { - if let clean::TupleVariant(ref tys) = var.kind { + if let clean::VariantKind::Tuple(ref tys) = var.kind { write!(w, "(")?; for (i, ty) in tys.iter().enumerate() { if i > 0 { @@ -2450,8 +2454,10 @@ fn item_enum(w: &mut fmt::Formatter, cx: &Context, it: &clean::Item, write!(w, "")?; document(w, cx, variant)?; - use clean::{Variant, StructVariant}; - if let clean::VariantItem( Variant { kind: StructVariant(ref s) } ) = variant.inner { + use clean::{Variant, VariantKind}; + if let clean::VariantItem(Variant { + kind: VariantKind::Struct(ref s) + }) = variant.inner { write!(w, "

Fields

\n ")?; for field in &s.fields { @@ -2740,7 +2746,7 @@ fn render_impl(w: &mut fmt::Formatter, cx: &Context, i: &Impl, link: AssocItemLi link: AssocItemLink, render_mode: RenderMode, is_default_item: bool, outer_version: Option<&str>, trait_: Option<&clean::Trait>) -> fmt::Result { - let item_type = item_type(item); + let item_type = item.type_(); let name = item.name.as_ref().unwrap(); let render_method_item: bool = match render_mode { @@ -2918,7 +2924,7 @@ impl<'a> fmt::Display for Sidebar<'a> { write!(fmt, "::")?; } write!(fmt, "{}", - &cx.root_path[..(cx.current.len() - i - 1) * 3], + &cx.root_path()[..(cx.current.len() - i - 1) * 3], *name)?; } write!(fmt, "

")?; @@ -2932,7 +2938,7 @@ impl<'a> fmt::Display for Sidebar<'a> { relpath: '{path}'\ }};", name = it.name.as_ref().map(|x| &x[..]).unwrap_or(""), - ty = item_type(it).css_class(), + ty = it.type_().css_class(), path = relpath)?; if parentlen == 0 { // there is no sidebar-items.js beyond the crate root path diff --git a/src/librustdoc/html/static/playpen.js b/src/librustdoc/html/static/playpen.js deleted file mode 100644 index cad97c04e1..0000000000 --- a/src/librustdoc/html/static/playpen.js +++ /dev/null @@ -1,43 +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. - -/*jslint browser: true, es5: true */ -/*globals $: true, rootPath: true */ - -document.addEventListener('DOMContentLoaded', function() { - 'use strict'; - - if (!window.playgroundUrl) { - return; - } - - var featureRegexp = new RegExp('^\s*#!\\[feature\\(\.*?\\)\\]'); - var elements = document.querySelectorAll('pre.rust-example-rendered'); - - Array.prototype.forEach.call(elements, function(el) { - el.onmouseover = function(e) { - if (el.contains(e.relatedTarget)) { - return; - } - - var a = el.querySelectorAll('a.test-arrow')[0]; - - var code = el.previousElementSibling.textContent; - - var channel = ''; - if (featureRegexp.test(code)) { - channel = '&version=nightly'; - } - - a.setAttribute('href', window.playgroundUrl + '?code=' + - encodeURIComponent(code) + channel); - }; - }); -}); diff --git a/src/librustdoc/html/static/rustdoc.css b/src/librustdoc/html/static/rustdoc.css index cad5fae690..f49b8556f6 100644 --- a/src/librustdoc/html/static/rustdoc.css +++ b/src/librustdoc/html/static/rustdoc.css @@ -570,8 +570,11 @@ pre.rust .self, pre.rust .bool-val, pre.rust .prelude-val, pre.rust .attribute, pre.rust .attribute .ident { color: #C82829; } pre.rust .macro, pre.rust .macro-nonterminal { color: #3E999F; } pre.rust .lifetime { color: #B76514; } +pre.rust .question-mark { + color: #ff9011; + font-weight: bold; +} -.rusttest { display: none; } pre.rust { position: relative; } a.test-arrow { background-color: rgba(78, 139, 202, 0.2); @@ -585,6 +588,7 @@ a.test-arrow { } a.test-arrow:hover{ background-color: #4e8bca; + text-decoration: none; } .section-header:hover a:after { diff --git a/src/librustdoc/html/toc.rs b/src/librustdoc/html/toc.rs index 305e6258ba..a7da1c5cca 100644 --- a/src/librustdoc/html/toc.rs +++ b/src/librustdoc/html/toc.rs @@ -247,7 +247,7 @@ mod tests { macro_rules! toc { ($(($level: expr, $name: expr, $(($sub: tt))* )),*) => { Toc { - entries: vec!( + entries: vec![ $( TocEntry { level: $level, @@ -257,7 +257,7 @@ mod tests { children: toc!($($sub),*) } ),* - ) + ] } } } diff --git a/src/librustdoc/lib.rs b/src/librustdoc/lib.rs index b6dc755ed9..ee395e0616 100644 --- a/src/librustdoc/lib.rs +++ b/src/librustdoc/lib.rs @@ -20,7 +20,7 @@ #![feature(box_patterns)] #![feature(box_syntax)] -#![feature(dotdot_in_tuple_patterns)] +#![cfg_attr(stage0, feature(dotdot_in_tuple_patterns))] #![feature(libc)] #![feature(rustc_private)] #![feature(set_stdio)] @@ -111,7 +111,7 @@ fn unstable(g: getopts::OptGroup) -> RustcOptGroup { RustcOptGroup::unstable(g) pub fn opts() -> Vec { use getopts::*; - vec!( + vec![ stable(optflag("h", "help", "show this help message")), stable(optflag("V", "version", "print rustdoc's version")), stable(optflag("v", "verbose", "use verbose output")), @@ -162,7 +162,7 @@ pub fn opts() -> Vec { unstable(optmulti("Z", "", "internal and debugging options (only on nightly build)", "FLAG")), stable(optopt("", "sysroot", "Override the system root", "PATH")), - ) + ] } pub fn usage(argv0: &str) { @@ -288,15 +288,14 @@ pub fn main_args(args: &[String]) -> isize { passes.into_iter().collect(), css_file_extension, renderinfo) - .expect("failed to generate documentation") + .expect("failed to generate documentation"); + 0 } Some(s) => { println!("unknown output format: {}", s); - return 1; + 1 } } - - return 0; } /// Looks inside the command line arguments to extract the relevant input format diff --git a/src/librustdoc/markdown.rs b/src/librustdoc/markdown.rs index 1421a3c78f..b617acfabb 100644 --- a/src/librustdoc/markdown.rs +++ b/src/librustdoc/markdown.rs @@ -19,7 +19,7 @@ use testing; use rustc::session::search_paths::SearchPaths; use rustc::session::config::Externs; -use externalfiles::ExternalHtml; +use externalfiles::{ExternalHtml, LoadStringError, load_string}; use html::render::reset_ids; use html::escape::Escape; @@ -58,12 +58,14 @@ pub fn render(input: &str, mut output: PathBuf, matches: &getopts::Matches, css.push_str(&s) } - 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() = Some(None); }); + let input_str = match load_string(input) { + Ok(s) => s, + Err(LoadStringError::ReadFail) => return 1, + Err(LoadStringError::BadUtf8) => return 2, + }; + if let Some(playground) = matches.opt_str("markdown-playground-url") { + markdown::PLAYGROUND.with(|s| { *s.borrow_mut() = Some((None, playground)); }); } - let playground = playground.unwrap_or("".to_string()); let mut out = match File::create(&output) { Err(e) => { @@ -115,9 +117,6 @@ pub fn render(input: &str, mut output: PathBuf, matches: &getopts::Matches, {before_content}

{title}

{text} - {after_content} "#, @@ -127,7 +126,6 @@ pub fn render(input: &str, mut output: PathBuf, matches: &getopts::Matches, before_content = external_html.before_content, text = rendered, after_content = external_html.after_content, - playground = playground, ); match err { @@ -144,7 +142,11 @@ pub fn render(input: &str, mut output: PathBuf, matches: &getopts::Matches, /// Run any tests/code examples in the markdown file `input`. pub fn test(input: &str, cfgs: Vec, libs: SearchPaths, externs: Externs, mut test_args: Vec) -> isize { - let input_str = load_or_return!(input, 1, 2); + let input_str = match load_string(input) { + Ok(s) => s, + Err(LoadStringError::ReadFail) => return 1, + Err(LoadStringError::BadUtf8) => return 2, + }; let mut opts = TestOptions::default(); opts.no_crate_inject = true; diff --git a/src/librustdoc/passes/mod.rs b/src/librustdoc/passes/mod.rs index a1b330e9b8..1cc4f9371c 100644 --- a/src/librustdoc/passes/mod.rs +++ b/src/librustdoc/passes/mod.rs @@ -131,7 +131,7 @@ impl<'a> fold::DocFolder for Stripper<'a> { clean::ImplItem(ref imp) if imp.trait_.is_some() => true, // Struct variant fields have inherited visibility clean::VariantItem(clean::Variant { - kind: clean::StructVariant(..) + kind: clean::VariantKind::Struct(..) }) => true, _ => false, }; diff --git a/src/librustdoc/test.rs b/src/librustdoc/test.rs index 1ab86cf7e8..1bbd67fb9b 100644 --- a/src/librustdoc/test.rs +++ b/src/librustdoc/test.rs @@ -66,31 +66,27 @@ pub fn run(input: &str, maybe_sysroot: Some(env::current_exe().unwrap().parent().unwrap() .parent().unwrap().to_path_buf()), search_paths: libs.clone(), - crate_types: vec!(config::CrateTypeDylib), + crate_types: vec![config::CrateTypeDylib], externs: externs.clone(), unstable_features: UnstableFeatures::from_environment(), ..config::basic_options().clone() }; let codemap = Rc::new(CodeMap::new()); - let diagnostic_handler = errors::Handler::with_tty_emitter(ColorConfig::Auto, - true, - false, - Some(codemap.clone())); + let handler = + errors::Handler::with_tty_emitter(ColorConfig::Auto, true, false, Some(codemap.clone())); let dep_graph = DepGraph::new(false); let _ignore = dep_graph.in_ignore(); let cstore = Rc::new(CStore::new(&dep_graph)); - let sess = session::build_session_(sessopts, - &dep_graph, - Some(input_path.clone()), - diagnostic_handler, - codemap, - cstore.clone()); + let mut sess = session::build_session_( + sessopts, &dep_graph, Some(input_path.clone()), handler, codemap, cstore.clone(), + ); rustc_lint::register_builtins(&mut sess.lint_store.borrow_mut(), Some(&sess)); + sess.parse_sess.config = + config::build_configuration(&sess, config::parse_cfgspecs(cfgs.clone())); - let cfg = config::build_configuration(&sess, config::parse_cfgspecs(cfgs.clone())); - let krate = panictry!(driver::phase_1_parse_input(&sess, cfg, &input)); + let krate = panictry!(driver::phase_1_parse_input(&sess, &input)); let driver::ExpansionResult { defs, mut hir_forest, .. } = { phase_2_configure_and_expand( &sess, &cstore, krate, None, "rustdoc-test", None, MakeGlobMap::No, |_| Ok(()) @@ -169,7 +165,7 @@ fn scrape_test_config(krate: &::rustc::hir::Crate) -> TestOptions { } } - return opts; + opts } fn runtest(test: &str, cratename: &str, cfgs: Vec, libs: SearchPaths, @@ -189,7 +185,7 @@ fn runtest(test: &str, cratename: &str, cfgs: Vec, libs: SearchPaths, maybe_sysroot: Some(env::current_exe().unwrap().parent().unwrap() .parent().unwrap().to_path_buf()), search_paths: libs, - crate_types: vec!(config::CrateTypeExecutable), + crate_types: vec![config::CrateTypeExecutable], output_types: outputs, externs: externs, cg: config::CodegenOptions { @@ -228,7 +224,7 @@ fn runtest(test: &str, cratename: &str, cfgs: Vec, libs: SearchPaths, let codemap = Rc::new(CodeMap::new()); let emitter = errors::emitter::EmitterWriter::new(box Sink(data.clone()), Some(codemap.clone())); - let old = io::set_panic(box Sink(data.clone())); + let old = io::set_panic(Some(box Sink(data.clone()))); let _bomb = Bomb(data.clone(), old.unwrap_or(box io::stdout())); // Compile the code @@ -236,18 +232,16 @@ fn runtest(test: &str, cratename: &str, cfgs: Vec, libs: SearchPaths, let dep_graph = DepGraph::new(false); let cstore = Rc::new(CStore::new(&dep_graph)); - let sess = session::build_session_(sessopts, - &dep_graph, - None, - diagnostic_handler, - codemap, - cstore.clone()); + let mut sess = session::build_session_( + sessopts, &dep_graph, None, diagnostic_handler, codemap, cstore.clone(), + ); rustc_lint::register_builtins(&mut sess.lint_store.borrow_mut(), Some(&sess)); let outdir = Mutex::new(TempDir::new("rustdoctest").ok().expect("rustdoc needs a tempdir")); let libdir = sess.target_filesearch(PathKind::All).get_lib_path(); let mut control = driver::CompileController::basic(); - let cfg = config::build_configuration(&sess, config::parse_cfgspecs(cfgs.clone())); + sess.parse_sess.config = + config::build_configuration(&sess, config::parse_cfgspecs(cfgs.clone())); let out = Some(outdir.lock().unwrap().path().to_path_buf()); if no_run { @@ -255,18 +249,16 @@ fn runtest(test: &str, cratename: &str, cfgs: Vec, libs: SearchPaths, } let res = panic::catch_unwind(AssertUnwindSafe(|| { - driver::compile_input(&sess, &cstore, cfg.clone(), - &input, &out, - &None, None, &control) + driver::compile_input(&sess, &cstore, &input, &out, &None, None, &control) })); match res { Ok(r) => { match r { Err(count) => { - if count > 0 && compile_fail == false { + if count > 0 && !compile_fail { sess.fatal("aborting due to previous error(s)") - } else if count == 0 && compile_fail == true { + } else if count == 0 && compile_fail { panic!("test compiled while it wasn't supposed to") } if count > 0 && error_codes.len() > 0 { @@ -279,7 +271,7 @@ fn runtest(test: &str, cratename: &str, cfgs: Vec, libs: SearchPaths, } } Err(_) => { - if compile_fail == false { + if !compile_fail { panic!("couldn't compile the test"); } if error_codes.len() > 0 { @@ -355,7 +347,7 @@ pub fn maketest(s: &str, cratename: Option<&str>, dont_insert_main: bool, if dont_insert_main || s.contains("fn main") { prog.push_str(&everything_else); } else { - prog.push_str("fn main() {\n "); + prog.push_str("fn main() {\n"); prog.push_str(&everything_else); prog = prog.trim().into(); prog.push_str("\n}"); @@ -363,7 +355,7 @@ pub fn maketest(s: &str, cratename: Option<&str>, dont_insert_main: bool, info!("final test program: {}", prog); - return prog + prog } fn partition_source(s: &str) -> (String, String) { @@ -387,7 +379,7 @@ fn partition_source(s: &str) -> (String, String) { } } - return (before, after); + (before, after) } pub struct Collector { @@ -443,7 +435,7 @@ impl Collector { // compiler failures are test failures should_panic: testing::ShouldPanic::No, }, - testfn: testing::DynTestFn(box move|| { + testfn: testing::DynTestFn(box move |()| { runtest(&test, &cratename, cfgs, diff --git a/src/librustdoc/visit_ast.rs b/src/librustdoc/visit_ast.rs index a29566f7a0..4d1af16227 100644 --- a/src/librustdoc/visit_ast.rs +++ b/src/librustdoc/visit_ast.rs @@ -328,7 +328,7 @@ impl<'a, 'tcx> RustdocVisitor<'a, 'tcx> { _ => false, }; self.view_item_stack.remove(&def_node_id); - return ret; + ret } pub fn visit_item(&mut self, item: &hir::Item, diff --git a/src/librustdoc/visit_lib.rs b/src/librustdoc/visit_lib.rs index 285b47fe60..6d2830c561 100644 --- a/src/librustdoc/visit_lib.rs +++ b/src/librustdoc/visit_lib.rs @@ -66,11 +66,12 @@ impl<'a, 'b, 'tcx> LibEmbargoVisitor<'a, 'b, 'tcx> { pub fn visit_mod(&mut self, def_id: DefId) { for item in self.cstore.item_children(def_id) { - self.visit_item(item.def_id); + self.visit_item(item.def); } } - fn visit_item(&mut self, def_id: DefId) { + fn visit_item(&mut self, def: Def) { + let def_id = def.def_id(); let vis = self.cstore.visibility(def_id); let inherited_item_level = if vis == Visibility::Public { self.prev_level @@ -80,7 +81,7 @@ impl<'a, 'b, 'tcx> LibEmbargoVisitor<'a, 'b, 'tcx> { let item_level = self.update(def_id, inherited_item_level); - if let Some(Def::Mod(_)) = self.cstore.describe_def(def_id) { + if let Def::Mod(..) = def { let orig_level = self.prev_level; self.prev_level = item_level; diff --git a/src/libserialize/json.rs b/src/libserialize/json.rs index 6ccc0be41b..239d32c8fc 100644 --- a/src/libserialize/json.rs +++ b/src/libserialize/json.rs @@ -199,6 +199,7 @@ use self::DecoderError::*; use self::ParserState::*; use self::InternalStackElement::*; +use std::borrow::Cow; use std::collections::{HashMap, BTreeMap}; use std::io::prelude::*; use std::io; @@ -433,9 +434,7 @@ fn escape_str(wr: &mut fmt::Write, v: &str) -> EncodeResult { } fn escape_char(writer: &mut fmt::Write, v: char) -> EncodeResult { - escape_str(writer, unsafe { - str::from_utf8_unchecked(v.encode_utf8().as_slice()) - }) + escape_str(writer, v.encode_utf8(&mut [0; 4])) } fn spaces(wr: &mut fmt::Write, mut n: usize) -> EncodeResult { @@ -2083,9 +2082,7 @@ impl Decoder { pub fn new(json: Json) -> Decoder { Decoder { stack: vec![json] } } -} -impl Decoder { fn pop(&mut self) -> Json { self.stack.pop().unwrap() } @@ -2184,8 +2181,8 @@ impl ::Decoder for Decoder { Err(ExpectedError("single character string".to_owned(), format!("{}", s))) } - fn read_str(&mut self) -> DecodeResult { - expect!(self.pop(), String) + fn read_str(&mut self) -> DecodeResult> { + expect!(self.pop(), String).map(Cow::Owned) } fn read_enum(&mut self, _name: &str, f: F) -> DecodeResult where @@ -3883,8 +3880,8 @@ mod tests { use std::collections::{HashMap,BTreeMap}; use super::ToJson; - let array2 = Array(vec!(U64(1), U64(2))); - let array3 = Array(vec!(U64(1), U64(2), U64(3))); + let array2 = Array(vec![U64(1), U64(2)]); + let array3 = Array(vec![U64(1), U64(2), U64(3)]); let object = { let mut tree_map = BTreeMap::new(); tree_map.insert("a".to_string(), U64(1)); @@ -3918,7 +3915,7 @@ mod tests { assert_eq!([1_usize, 2_usize].to_json(), array2); assert_eq!((&[1_usize, 2_usize, 3_usize]).to_json(), array3); assert_eq!((vec![1_usize, 2_usize]).to_json(), array2); - assert_eq!(vec!(1_usize, 2_usize, 3_usize).to_json(), array3); + assert_eq!(vec![1_usize, 2_usize, 3_usize].to_json(), array3); let mut tree_map = BTreeMap::new(); tree_map.insert("a".to_string(), 1 as usize); tree_map.insert("b".to_string(), 2); diff --git a/src/libserialize/leb128.rs b/src/libserialize/leb128.rs index 0c5356c022..8e8e03f1f8 100644 --- a/src/libserialize/leb128.rs +++ b/src/libserialize/leb128.rs @@ -38,6 +38,7 @@ pub fn write_unsigned_leb128(out: &mut Vec, start_position: usize, mut value return position - start_position; } +#[inline] pub fn read_unsigned_leb128(data: &[u8], start_position: usize) -> (u64, usize) { let mut result = 0; let mut shift = 0; @@ -78,6 +79,7 @@ pub fn write_signed_leb128(out: &mut Vec, start_position: usize, mut value: return position - start_position; } +#[inline] pub fn read_signed_leb128(data: &[u8], start_position: usize) -> (i64, usize) { let mut result = 0; let mut shift = 0; diff --git a/src/libserialize/opaque.rs b/src/libserialize/opaque.rs index e97834f63c..87b6ed2ed4 100644 --- a/src/libserialize/opaque.rs +++ b/src/libserialize/opaque.rs @@ -9,6 +9,7 @@ // except according to those terms. use leb128::{read_signed_leb128, read_unsigned_leb128, write_signed_leb128, write_unsigned_leb128}; +use std::borrow::Cow; use std::io::{self, Write}; use serialize; @@ -178,79 +179,95 @@ macro_rules! read_sleb128 { impl<'a> serialize::Decoder for Decoder<'a> { type Error = String; + #[inline] fn read_nil(&mut self) -> Result<(), Self::Error> { Ok(()) } + #[inline] fn read_u64(&mut self) -> Result { read_uleb128!(self, u64) } + #[inline] fn read_u32(&mut self) -> Result { read_uleb128!(self, u32) } + #[inline] fn read_u16(&mut self) -> Result { read_uleb128!(self, u16) } + #[inline] fn read_u8(&mut self) -> Result { let value = self.data[self.position]; self.position += 1; Ok(value) } + #[inline] fn read_usize(&mut self) -> Result { read_uleb128!(self, usize) } + #[inline] fn read_i64(&mut self) -> Result { read_sleb128!(self, i64) } + #[inline] fn read_i32(&mut self) -> Result { read_sleb128!(self, i32) } + #[inline] fn read_i16(&mut self) -> Result { read_sleb128!(self, i16) } + #[inline] fn read_i8(&mut self) -> Result { let as_u8 = self.data[self.position]; self.position += 1; unsafe { Ok(::std::mem::transmute(as_u8)) } } + #[inline] fn read_isize(&mut self) -> Result { read_sleb128!(self, isize) } + #[inline] fn read_bool(&mut self) -> Result { let value = self.read_u8()?; Ok(value != 0) } + #[inline] fn read_f64(&mut self) -> Result { let bits = self.read_u64()?; Ok(unsafe { ::std::mem::transmute(bits) }) } + #[inline] fn read_f32(&mut self) -> Result { let bits = self.read_u32()?; Ok(unsafe { ::std::mem::transmute(bits) }) } + #[inline] fn read_char(&mut self) -> Result { let bits = self.read_u32()?; Ok(::std::char::from_u32(bits).unwrap()) } - fn read_str(&mut self) -> Result { + #[inline] + fn read_str(&mut self) -> Result, Self::Error> { let len = self.read_usize()?; let s = ::std::str::from_utf8(&self.data[self.position..self.position + len]).unwrap(); self.position += len; - Ok(s.to_string()) + Ok(Cow::Borrowed(s)) } fn error(&mut self, err: &str) -> Self::Error { diff --git a/src/libserialize/serialize.rs b/src/libserialize/serialize.rs index 6650a98188..c4613c661a 100644 --- a/src/libserialize/serialize.rs +++ b/src/libserialize/serialize.rs @@ -14,6 +14,7 @@ Core encoding and decoding interfaces. */ +use std::borrow::Cow; use std::intrinsics; use std::path; use std::rc::Rc; @@ -156,7 +157,7 @@ pub trait Decoder { fn read_f64(&mut self) -> Result; fn read_f32(&mut self) -> Result; fn read_char(&mut self) -> Result; - fn read_str(&mut self) -> Result; + fn read_str(&mut self) -> Result, Self::Error>; // Compound types: fn read_enum(&mut self, _name: &str, f: F) -> Result @@ -401,7 +402,7 @@ impl Encodable for String { impl Decodable for String { fn decode(d: &mut D) -> Result { - d.read_str() + Ok(d.read_str()?.into_owned()) } } diff --git a/src/libstd/build.rs b/src/libstd/build.rs index c5732278db..72cd6e4830 100644 --- a/src/libstd/build.rs +++ b/src/libstd/build.rs @@ -26,7 +26,7 @@ fn main() { let target = env::var("TARGET").expect("TARGET was not set"); let host = env::var("HOST").expect("HOST was not set"); if cfg!(feature = "backtrace") && !target.contains("apple") && !target.contains("msvc") && - !target.contains("emscripten") { + !target.contains("emscripten") && !target.contains("fuchsia") { build_libbacktrace(&host, &target); } @@ -58,6 +58,8 @@ fn main() { println!("cargo:rustc-link-lib=ws2_32"); println!("cargo:rustc-link-lib=userenv"); println!("cargo:rustc-link-lib=shell32"); + } else if target.contains("fuchsia") { + println!("cargo:rustc-link-lib=magenta"); } } diff --git a/src/libstd/collections/hash/bench.rs b/src/libstd/collections/hash/bench.rs index a1275d23d5..ff6cb7985a 100644 --- a/src/libstd/collections/hash/bench.rs +++ b/src/libstd/collections/hash/bench.rs @@ -15,17 +15,17 @@ extern crate test; use self::test::Bencher; #[bench] -fn new_drop(b : &mut Bencher) { +fn new_drop(b: &mut Bencher) { use super::map::HashMap; b.iter(|| { - let m : HashMap = HashMap::new(); + let m: HashMap = HashMap::new(); assert_eq!(m.len(), 0); }) } #[bench] -fn new_insert_drop(b : &mut Bencher) { +fn new_insert_drop(b: &mut Bencher) { use super::map::HashMap; b.iter(|| { diff --git a/src/libstd/collections/hash/map.rs b/src/libstd/collections/hash/map.rs index 5772e69b23..ece51d6d82 100644 --- a/src/libstd/collections/hash/map.rs +++ b/src/libstd/collections/hash/map.rs @@ -11,6 +11,7 @@ use self::Entry::*; use self::VacantEntryState::*; +use cell::Cell; use borrow::Borrow; use cmp::max; use fmt::{self, Debug}; @@ -21,27 +22,12 @@ use mem::{self, replace}; use ops::{Deref, Index}; use rand::{self, Rng}; -use super::table::{ - self, - Bucket, - EmptyBucket, - FullBucket, - FullBucketMut, - RawTable, - SafeHash -}; -use super::table::BucketState::{ - Empty, - Full, -}; - -const INITIAL_LOG2_CAP: usize = 5; -const INITIAL_CAPACITY: usize = 1 << INITIAL_LOG2_CAP; // 2^5 - -/// The default behavior of HashMap implements a load factor of 90.9%. -/// This behavior is characterized by the following condition: -/// -/// - if size > 0.909 * capacity: grow the map +use super::table::{self, Bucket, EmptyBucket, FullBucket, FullBucketMut, RawTable, SafeHash}; +use super::table::BucketState::{Empty, Full}; + +const MIN_NONZERO_RAW_CAPACITY: usize = 32; // must be a power of two + +/// The default behavior of HashMap implements a maximum load factor of 90.9%. #[derive(Clone)] struct DefaultResizePolicy; @@ -50,40 +36,35 @@ impl DefaultResizePolicy { DefaultResizePolicy } + /// A hash map's "capacity" is the number of elements it can hold without + /// being resized. Its "raw capacity" is the number of slots required to + /// provide that capacity, accounting for maximum loading. The raw capacity + /// is always zero or a power of two. #[inline] - fn min_capacity(&self, usable_size: usize) -> usize { - // Here, we are rephrasing the logic by specifying the lower limit - // on capacity: - // - // - if `cap < size * 1.1`: grow the map - usable_size * 11 / 10 + fn raw_capacity(&self, len: usize) -> usize { + if len == 0 { + 0 + } else { + // 1. Account for loading: `raw_capacity >= len * 1.1`. + // 2. Ensure it is a power of two. + // 3. Ensure it is at least the minimum size. + let mut raw_cap = len * 11 / 10; + assert!(raw_cap >= len, "raw_cap overflow"); + raw_cap = raw_cap.checked_next_power_of_two().expect("raw_capacity overflow"); + raw_cap = max(MIN_NONZERO_RAW_CAPACITY, raw_cap); + raw_cap + } } - /// An inverse of `min_capacity`, approximately. + /// The capacity of the given raw capacity. #[inline] - fn usable_capacity(&self, cap: usize) -> usize { - // As the number of entries approaches usable capacity, - // min_capacity(size) must be smaller than the internal capacity, - // so that the map is not resized: - // `min_capacity(usable_capacity(x)) <= x`. - // The left-hand side can only be smaller due to flooring by integer - // division. - // + fn capacity(&self, raw_cap: usize) -> usize { // This doesn't have to be checked for overflow since allocation size // in bytes will overflow earlier than multiplication by 10. // // As per https://github.com/rust-lang/rust/pull/30991 this is updated - // to be: (cap * den + den - 1) / num - (cap * 10 + 10 - 1) / 11 - } -} - -#[test] -fn test_resize_policy() { - let rp = DefaultResizePolicy; - for n in 0..1000 { - assert!(rp.min_capacity(rp.usable_capacity(n)) <= n); - assert!(rp.usable_capacity(rp.min_capacity(n)) <= n); + // to be: (raw_cap * den + den - 1) / num + (raw_cap * 10 + 10 - 1) / 11 } } @@ -197,15 +178,29 @@ fn test_resize_policy() { // // FIXME(Gankro, pczarn): review the proof and put it all in a separate README.md -/// A hash map implementation which uses linear probing with Robin -/// Hood bucket stealing. +/// A hash map implementation which uses linear probing with Robin Hood bucket +/// stealing. /// -/// By default, HashMap uses a somewhat slow hashing algorithm which can provide resistance -/// to DoS attacks. Rust makes a best attempt at acquiring random numbers without IO -/// blocking from your system. Because of this HashMap is not guaranteed to provide -/// DoS resistance since the numbers generated might not be truly random. If you do -/// require this behavior you can create your own hashing function using -/// [BuildHasherDefault](../hash/struct.BuildHasherDefault.html). +/// By default, `HashMap` uses a hashing algorithm selected to provide +/// resistance against HashDoS attacks. The algorithm is randomly seeded, and a +/// reasonable best-effort is made to generate this seed from a high quality, +/// secure source of randomness provided by the host without blocking the +/// program. Because of this, the randomness of the seed is dependant on the +/// quality of the system's random number generator at the time it is created. +/// In particular, seeds generated when the system's entropy pool is abnormally +/// low such as during system boot may be of a lower quality. +/// +/// The default hashing algorithm is currently SipHash 1-3, though this is +/// subject to change at any point in the future. While its performance is very +/// competitive for medium sized keys, other hashing algorithms will outperform +/// it for small keys such as integers as well as large keys such as long +/// strings, though those algorithms will typically *not* protect against +/// attacks such as HashDoS. +/// +/// The hashing algorithm can be replaced on a per-`HashMap` basis using the +/// `HashMap::default`, `HashMap::with_hasher`, and +/// `HashMap::with_capacity_and_hasher` methods. Many alternative algorithms +/// are available on crates.io, such as the `fnv` crate. /// /// It is required that the keys implement the [`Eq`] and [`Hash`] traits, although /// this can frequently be achieved by using `#[derive(PartialEq, Eq, Hash)]`. @@ -336,6 +331,22 @@ fn test_resize_policy() { /// println!("{:?} has {} hp", viking, health); /// } /// ``` +/// +/// A HashMap with fixed list of elements can be initialized from an array: +/// +/// ``` +/// use std::collections::HashMap; +/// +/// fn main() { +/// let timber_resources: HashMap<&str, i32> = +/// [("Norway", 100), +/// ("Denmark", 50), +/// ("Iceland", 10)] +/// .iter().cloned().collect(); +/// // use the values stored in map +/// } +/// ``` + #[derive(Clone)] #[stable(feature = "rust1", since = "1.0.0")] pub struct HashMap { @@ -349,12 +360,9 @@ pub struct HashMap { /// Search for a pre-hashed key. #[inline] -fn search_hashed(table: M, - hash: SafeHash, - mut is_match: F) - -> InternalEntry where - M: Deref>, - F: FnMut(&K) -> bool, +fn search_hashed(table: M, hash: SafeHash, mut is_match: F) -> InternalEntry + where M: Deref>, + F: FnMut(&K) -> bool { // This is the only function where capacity can be zero. To avoid // undefined behavior when Bucket::new gets the raw bucket in this @@ -376,7 +384,7 @@ fn search_hashed(table: M, elem: NoElem(bucket), }; } - Full(bucket) => bucket + Full(bucket) => bucket, }; let robin_ib = full.index() as isize - full.displacement() as isize; @@ -395,9 +403,7 @@ fn search_hashed(table: M, if hash == full.hash() { // If the key doesn't match, it can't be this one.. if is_match(full.read().0) { - return InternalEntry::Occupied { - elem: full - }; + return InternalEntry::Occupied { elem: full }; } } @@ -410,13 +416,13 @@ fn pop_internal(starting_bucket: FullBucketMut) -> (K, V) { let (empty, retkey, retval) = starting_bucket.take(); let mut gap = match empty.gap_peek() { Some(b) => b, - None => return (retkey, retval) + None => return (retkey, retval), }; while gap.full().displacement() != 0 { gap = match gap.shift() { Some(b) => b, - None => break + None => break, }; } @@ -430,11 +436,11 @@ fn pop_internal(starting_bucket: FullBucketMut) -> (K, V) { /// /// `hash`, `k`, and `v` are the elements to "robin hood" into the hashtable. fn robin_hood<'a, K: 'a, V: 'a>(bucket: FullBucketMut<'a, K, V>, - mut ib: usize, - mut hash: SafeHash, - mut key: K, - mut val: V) - -> &'a mut V { + mut ib: usize, + mut hash: SafeHash, + mut key: K, + mut val: V) + -> &'a mut V { let starting_index = bucket.index(); let size = bucket.table().size(); // Save the *starting point*. @@ -466,8 +472,8 @@ fn robin_hood<'a, K: 'a, V: 'a>(bucket: FullBucketMut<'a, K, V>, // FullBucketMut, into just one FullBucketMut. The "table" // refers to the inner FullBucketMut in this context. return bucket.into_table().into_mut_refs().1; - }, - Full(bucket) => bucket + } + Full(bucket) => bucket, }; let probe_ib = full_bucket.index() - full_bucket.displacement(); @@ -484,9 +490,12 @@ fn robin_hood<'a, K: 'a, V: 'a>(bucket: FullBucketMut<'a, K, V>, } impl HashMap - where K: Eq + Hash, S: BuildHasher + where K: Eq + Hash, + S: BuildHasher { - fn make_hash(&self, x: &X) -> SafeHash where X: Hash { + fn make_hash(&self, x: &X) -> SafeHash + where X: Hash + { table::make_hash(&self.hash_builder, x) } @@ -495,7 +504,8 @@ impl HashMap /// search_hashed. #[inline] fn search<'a, Q: ?Sized>(&'a self, q: &Q) -> InternalEntry> - where K: Borrow, Q: Eq + Hash + where K: Borrow, + Q: Eq + Hash { let hash = self.make_hash(q); search_hashed(&self.table, hash, |k| q.eq(k.borrow())) @@ -503,7 +513,8 @@ impl HashMap #[inline] fn search_mut<'a, Q: ?Sized>(&'a mut self, q: &Q) -> InternalEntry> - where K: Borrow, Q: Eq + Hash + where K: Borrow, + Q: Eq + Hash { let hash = self.make_hash(q); search_hashed(&mut self.table, hash, |k| q.eq(k.borrow())) @@ -511,11 +522,11 @@ impl HashMap // The caller should ensure that invariants by Robin Hood Hashing hold. fn insert_hashed_ordered(&mut self, hash: SafeHash, k: K, v: V) { - let cap = self.table.capacity(); + let raw_cap = self.raw_capacity(); let mut buckets = Bucket::new(&mut self.table, hash); let ib = buckets.index(); - while buckets.index() != ib + cap { + while buckets.index() != ib + raw_cap { // We don't need to compare hashes for value swap. // Not even DIBs for Robin Hood. buckets = match buckets.peek() { @@ -523,7 +534,7 @@ impl HashMap empty.put(hash, k, v); return; } - Full(b) => b.into_bucket() + Full(b) => b.into_bucket(), }; buckets.next(); } @@ -546,7 +557,10 @@ impl HashMap { Default::default() } - /// Creates an empty `HashMap` with the given initial capacity. + /// Creates an empty `HashMap` with the specified capacity. + /// + /// The hash map will be able to hold at least `capacity` elements without + /// reallocating. If `capacity` is 0, the hash map will not allocate. /// /// # Examples /// @@ -562,7 +576,8 @@ impl HashMap { } impl HashMap - where K: Eq + Hash, S: BuildHasher + where K: Eq + Hash, + S: BuildHasher { /// Creates an empty `HashMap` which will use the given hash builder to hash /// keys. @@ -594,9 +609,11 @@ impl HashMap } } - /// Creates an empty `HashMap` with space for at least `capacity` - /// elements, using `hasher` to hash the keys. + /// Creates an empty `HashMap` with the specified capacity, using `hasher` + /// to hash the keys. /// + /// The hash map will be able to hold at least `capacity` elements without + /// reallocating. If `capacity` is 0, the hash map will not allocate. /// Warning: `hasher` is normally randomly generated, and /// is designed to allow HashMaps to be resistant to attacks that /// cause many collisions and very poor performance. Setting it @@ -614,16 +631,13 @@ impl HashMap /// ``` #[inline] #[stable(feature = "hashmap_build_hasher", since = "1.7.0")] - pub fn with_capacity_and_hasher(capacity: usize, hash_builder: S) - -> HashMap { + pub fn with_capacity_and_hasher(capacity: usize, hash_builder: S) -> HashMap { let resize_policy = DefaultResizePolicy::new(); - let min_cap = max(INITIAL_CAPACITY, resize_policy.min_capacity(capacity)); - let internal_cap = min_cap.checked_next_power_of_two().expect("capacity overflow"); - assert!(internal_cap >= capacity, "capacity overflow"); + let raw_cap = resize_policy.raw_capacity(capacity); HashMap { hash_builder: hash_builder, resize_policy: resize_policy, - table: RawTable::new(internal_cap), + table: RawTable::new(raw_cap), } } @@ -648,7 +662,13 @@ impl HashMap #[inline] #[stable(feature = "rust1", since = "1.0.0")] pub fn capacity(&self) -> usize { - self.resize_policy.usable_capacity(self.table.capacity()) + self.resize_policy.capacity(self.raw_capacity()) + } + + /// Returns the hash map's raw capacity. + #[inline] + fn raw_capacity(&self) -> usize { + self.table.capacity() } /// Reserves capacity for at least `additional` more elements to be inserted @@ -668,28 +688,24 @@ impl HashMap /// ``` #[stable(feature = "rust1", since = "1.0.0")] pub fn reserve(&mut self, additional: usize) { - let new_size = self.len().checked_add(additional).expect("capacity overflow"); - let min_cap = self.resize_policy.min_capacity(new_size); - - // An invalid value shouldn't make us run out of space. This includes - // an overflow check. - assert!(new_size <= min_cap); - - if self.table.capacity() < min_cap { - let new_capacity = max(min_cap.next_power_of_two(), INITIAL_CAPACITY); - self.resize(new_capacity); + let remaining = self.capacity() - self.len(); // this can't overflow + if remaining < additional { + let min_cap = self.len().checked_add(additional).expect("reserve overflow"); + let raw_cap = self.resize_policy.raw_capacity(min_cap); + self.resize(raw_cap); } } - /// Resizes the internal vectors to a new capacity. It's your responsibility to: - /// 1) Make sure the new capacity is enough for all the elements, accounting + /// Resizes the internal vectors to a new capacity. It's your + /// responsibility to: + /// 1) Ensure `new_raw_cap` is enough for all the elements, accounting /// for the load factor. - /// 2) Ensure `new_capacity` is a power of two or zero. - fn resize(&mut self, new_capacity: usize) { - assert!(self.table.size() <= new_capacity); - assert!(new_capacity.is_power_of_two() || new_capacity == 0); + /// 2) Ensure `new_raw_cap` is a power of two or zero. + fn resize(&mut self, new_raw_cap: usize) { + assert!(self.table.size() <= new_raw_cap); + assert!(new_raw_cap.is_power_of_two() || new_raw_cap == 0); - let mut old_table = replace(&mut self.table, RawTable::new(new_capacity)); + let mut old_table = replace(&mut self.table, RawTable::new(new_raw_cap)); let old_size = old_table.size(); if old_table.capacity() == 0 || old_table.size() == 0 { @@ -753,7 +769,7 @@ impl HashMap } b.into_bucket() } - Empty(b) => b.into_bucket() + Empty(b) => b.into_bucket(), }; bucket.next(); } @@ -779,14 +795,9 @@ impl HashMap /// ``` #[stable(feature = "rust1", since = "1.0.0")] pub fn shrink_to_fit(&mut self) { - let min_capacity = self.resize_policy.min_capacity(self.len()); - let min_capacity = max(min_capacity.next_power_of_two(), INITIAL_CAPACITY); - - // An invalid value shouldn't make us run out of space. - debug_assert!(self.len() <= min_capacity); - - if self.table.capacity() != min_capacity { - let old_table = replace(&mut self.table, RawTable::new(min_capacity)); + let new_raw_cap = self.resize_policy.raw_capacity(self.len()); + if self.raw_capacity() != new_raw_cap { + let old_table = replace(&mut self.table, RawTable::new(new_raw_cap)); let old_size = old_table.size(); // Shrink the table. Naive algorithm for resizing: @@ -807,16 +818,12 @@ impl HashMap fn insert_hashed_nocheck(&mut self, hash: SafeHash, k: K, v: V) -> Option { let entry = search_hashed(&mut self.table, hash, |key| *key == k).into_entry(k); match entry { - Some(Occupied(mut elem)) => { - Some(elem.insert(v)) - } + Some(Occupied(mut elem)) => Some(elem.insert(v)), Some(Vacant(elem)) => { elem.insert(v); None } - None => { - unreachable!() - } + None => unreachable!(), } } @@ -980,7 +987,9 @@ impl HashMap /// assert_eq!(a.len(), 1); /// ``` #[stable(feature = "rust1", since = "1.0.0")] - pub fn len(&self) -> usize { self.table.size() } + pub fn len(&self) -> usize { + self.table.size() + } /// Returns true if the map contains no elements. /// @@ -996,7 +1005,9 @@ impl HashMap /// ``` #[inline] #[stable(feature = "rust1", since = "1.0.0")] - pub fn is_empty(&self) -> bool { self.len() == 0 } + pub fn is_empty(&self) -> bool { + self.len() == 0 + } /// Clears the map, returning all key-value pairs as an iterator. Keeps the /// allocated memory for reuse. @@ -1020,9 +1031,7 @@ impl HashMap #[inline] #[stable(feature = "drain", since = "1.6.0")] pub fn drain(&mut self) -> Drain { - Drain { - inner: self.table.drain(), - } + Drain { inner: self.table.drain() } } /// Clears the map, removing all key-value pairs. Keeps the allocated memory @@ -1065,7 +1074,8 @@ impl HashMap /// ``` #[stable(feature = "rust1", since = "1.0.0")] pub fn get(&self, k: &Q) -> Option<&V> - where K: Borrow, Q: Hash + Eq + where K: Borrow, + Q: Hash + Eq { self.search(k).into_occupied_bucket().map(|bucket| bucket.into_refs().1) } @@ -1091,7 +1101,8 @@ impl HashMap /// ``` #[stable(feature = "rust1", since = "1.0.0")] pub fn contains_key(&self, k: &Q) -> bool - where K: Borrow, Q: Hash + Eq + where K: Borrow, + Q: Hash + Eq { self.search(k).into_occupied_bucket().is_some() } @@ -1119,7 +1130,8 @@ impl HashMap /// ``` #[stable(feature = "rust1", since = "1.0.0")] pub fn get_mut(&mut self, k: &Q) -> Option<&mut V> - where K: Borrow, Q: Hash + Eq + where K: Borrow, + Q: Hash + Eq { self.search_mut(k).into_occupied_bucket().map(|bucket| bucket.into_mut_refs().1) } @@ -1177,10 +1189,11 @@ impl HashMap /// ``` #[stable(feature = "rust1", since = "1.0.0")] pub fn remove(&mut self, k: &Q) -> Option - where K: Borrow, Q: Hash + Eq + where K: Borrow, + Q: Hash + Eq { if self.table.size() == 0 { - return None + return None; } self.search_mut(k).into_occupied_bucket().map(|bucket| pop_internal(bucket).1) @@ -1189,25 +1202,32 @@ impl HashMap #[stable(feature = "rust1", since = "1.0.0")] impl PartialEq for HashMap - where K: Eq + Hash, V: PartialEq, S: BuildHasher + where K: Eq + Hash, + V: PartialEq, + S: BuildHasher { fn eq(&self, other: &HashMap) -> bool { - if self.len() != other.len() { return false; } + if self.len() != other.len() { + return false; + } - self.iter().all(|(key, value)| - other.get(key).map_or(false, |v| *value == *v) - ) + self.iter().all(|(key, value)| other.get(key).map_or(false, |v| *value == *v)) } } #[stable(feature = "rust1", since = "1.0.0")] impl Eq for HashMap - where K: Eq + Hash, V: Eq, S: BuildHasher -{} + where K: Eq + Hash, + V: Eq, + S: BuildHasher +{ +} #[stable(feature = "rust1", since = "1.0.0")] impl Debug for HashMap - where K: Eq + Hash + Debug, V: Debug, S: BuildHasher + where K: Eq + Hash + Debug, + V: Debug, + S: BuildHasher { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { f.debug_map().entries(self.iter()).finish() @@ -1217,7 +1237,7 @@ impl Debug for HashMap #[stable(feature = "rust1", since = "1.0.0")] impl Default for HashMap where K: Eq + Hash, - S: BuildHasher + Default, + S: BuildHasher + Default { /// Creates an empty `HashMap`, with the `Default` value for the hasher. fn default() -> HashMap { @@ -1229,7 +1249,7 @@ impl Default for HashMap impl<'a, K, Q: ?Sized, V, S> Index<&'a Q> for HashMap where K: Eq + Hash + Borrow, Q: Eq + Hash, - S: BuildHasher, + S: BuildHasher { type Output = V; @@ -1242,79 +1262,71 @@ impl<'a, K, Q: ?Sized, V, S> Index<&'a Q> for HashMap /// HashMap iterator. #[stable(feature = "rust1", since = "1.0.0")] pub struct Iter<'a, K: 'a, V: 'a> { - inner: table::Iter<'a, K, V> + inner: table::Iter<'a, K, V>, } // FIXME(#19839) Remove in favor of `#[derive(Clone)]` #[stable(feature = "rust1", since = "1.0.0")] impl<'a, K, V> Clone for Iter<'a, K, V> { fn clone(&self) -> Iter<'a, K, V> { - Iter { - inner: self.inner.clone() - } + Iter { inner: self.inner.clone() } } } /// HashMap mutable values iterator. #[stable(feature = "rust1", since = "1.0.0")] pub struct IterMut<'a, K: 'a, V: 'a> { - inner: table::IterMut<'a, K, V> + inner: table::IterMut<'a, K, V>, } /// HashMap move iterator. #[stable(feature = "rust1", since = "1.0.0")] pub struct IntoIter { - inner: table::IntoIter + inner: table::IntoIter, } /// HashMap keys iterator. #[stable(feature = "rust1", since = "1.0.0")] pub struct Keys<'a, K: 'a, V: 'a> { - inner: Iter<'a, K, V> + inner: Iter<'a, K, V>, } // FIXME(#19839) Remove in favor of `#[derive(Clone)]` #[stable(feature = "rust1", since = "1.0.0")] impl<'a, K, V> Clone for Keys<'a, K, V> { fn clone(&self) -> Keys<'a, K, V> { - Keys { - inner: self.inner.clone() - } + Keys { inner: self.inner.clone() } } } /// HashMap values iterator. #[stable(feature = "rust1", since = "1.0.0")] pub struct Values<'a, K: 'a, V: 'a> { - inner: Iter<'a, K, V> + inner: Iter<'a, K, V>, } // FIXME(#19839) Remove in favor of `#[derive(Clone)]` #[stable(feature = "rust1", since = "1.0.0")] impl<'a, K, V> Clone for Values<'a, K, V> { fn clone(&self) -> Values<'a, K, V> { - Values { - inner: self.inner.clone() - } + Values { inner: self.inner.clone() } } } /// HashMap drain iterator. #[stable(feature = "drain", since = "1.6.0")] pub struct Drain<'a, K: 'a, V: 'a> { - inner: table::Drain<'a, K, V> + inner: table::Drain<'a, K, V>, } /// Mutable HashMap values iterator. #[stable(feature = "map_values_mut", since = "1.10.0")] pub struct ValuesMut<'a, K: 'a, V: 'a> { - inner: IterMut<'a, K, V> + inner: IterMut<'a, K, V>, } enum InternalEntry { - Occupied { - elem: FullBucket, - }, + Occupied { elem: FullBucket }, Vacant { hash: SafeHash, elem: VacantEntryState, @@ -1339,7 +1351,7 @@ impl<'a, K, V> InternalEntry> { InternalEntry::Occupied { elem } => { Some(Occupied(OccupiedEntry { key: Some(key), - elem: elem + elem: elem, })) } InternalEntry::Vacant { hash, elem } => { @@ -1349,7 +1361,7 @@ impl<'a, K, V> InternalEntry> { elem: elem, })) } - InternalEntry::TableIsEmpty => None + InternalEntry::TableIsEmpty => None, } } } @@ -1363,27 +1375,29 @@ impl<'a, K, V> InternalEntry> { pub enum Entry<'a, K: 'a, V: 'a> { /// An occupied Entry. #[stable(feature = "rust1", since = "1.0.0")] - Occupied( - #[stable(feature = "rust1", since = "1.0.0")] OccupiedEntry<'a, K, V> - ), + Occupied(#[stable(feature = "rust1", since = "1.0.0")] + OccupiedEntry<'a, K, V>), /// A vacant Entry. #[stable(feature = "rust1", since = "1.0.0")] - Vacant( - #[stable(feature = "rust1", since = "1.0.0")] VacantEntry<'a, K, V> - ), + Vacant(#[stable(feature = "rust1", since = "1.0.0")] + VacantEntry<'a, K, V>), } #[stable(feature= "debug_hash_map", since = "1.12.0")] impl<'a, K: 'a + Debug, V: 'a + Debug> Debug for Entry<'a, K, V> { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { match *self { - Vacant(ref v) => f.debug_tuple("Entry") - .field(v) - .finish(), - Occupied(ref o) => f.debug_tuple("Entry") - .field(o) - .finish(), + Vacant(ref v) => { + f.debug_tuple("Entry") + .field(v) + .finish() + } + Occupied(ref o) => { + f.debug_tuple("Entry") + .field(o) + .finish() + } } } } @@ -1402,9 +1416,9 @@ pub struct OccupiedEntry<'a, K: 'a, V: 'a> { impl<'a, K: 'a + Debug, V: 'a + Debug> Debug for OccupiedEntry<'a, K, V> { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { f.debug_struct("OccupiedEntry") - .field("key", self.key()) - .field("value", self.get()) - .finish() + .field("key", self.key()) + .field("value", self.get()) + .finish() } } @@ -1423,8 +1437,8 @@ pub struct VacantEntry<'a, K: 'a, V: 'a> { impl<'a, K: 'a + Debug, V: 'a> Debug for VacantEntry<'a, K, V> { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { f.debug_tuple("VacantEntry") - .field(self.key()) - .finish() + .field(self.key()) + .finish() } } @@ -1439,7 +1453,8 @@ enum VacantEntryState { #[stable(feature = "rust1", since = "1.0.0")] impl<'a, K, V, S> IntoIterator for &'a HashMap - where K: Eq + Hash, S: BuildHasher + where K: Eq + Hash, + S: BuildHasher { type Item = (&'a K, &'a V); type IntoIter = Iter<'a, K, V>; @@ -1451,7 +1466,8 @@ impl<'a, K, V, S> IntoIterator for &'a HashMap #[stable(feature = "rust1", since = "1.0.0")] impl<'a, K, V, S> IntoIterator for &'a mut HashMap - where K: Eq + Hash, S: BuildHasher + where K: Eq + Hash, + S: BuildHasher { type Item = (&'a K, &'a mut V); type IntoIter = IterMut<'a, K, V>; @@ -1463,7 +1479,8 @@ impl<'a, K, V, S> IntoIterator for &'a mut HashMap #[stable(feature = "rust1", since = "1.0.0")] impl IntoIterator for HashMap - where K: Eq + Hash, S: BuildHasher + where K: Eq + Hash, + S: BuildHasher { type Item = (K, V); type IntoIter = IntoIter; @@ -1486,9 +1503,7 @@ impl IntoIterator for HashMap /// let vec: Vec<(&str, isize)> = map.into_iter().collect(); /// ``` fn into_iter(self) -> IntoIter { - IntoIter { - inner: self.table.into_iter() - } + IntoIter { inner: self.table.into_iter() } } } @@ -1496,12 +1511,21 @@ impl IntoIterator for HashMap impl<'a, K, V> Iterator for Iter<'a, K, V> { type Item = (&'a K, &'a V); - #[inline] fn next(&mut self) -> Option<(&'a K, &'a V)> { self.inner.next() } - #[inline] fn size_hint(&self) -> (usize, Option) { self.inner.size_hint() } + #[inline] + fn next(&mut self) -> Option<(&'a K, &'a V)> { + self.inner.next() + } + #[inline] + fn size_hint(&self) -> (usize, Option) { + self.inner.size_hint() + } } #[stable(feature = "rust1", since = "1.0.0")] impl<'a, K, V> ExactSizeIterator for Iter<'a, K, V> { - #[inline] fn len(&self) -> usize { self.inner.len() } + #[inline] + fn len(&self) -> usize { + self.inner.len() + } } #[unstable(feature = "fused", issue = "35602")] @@ -1511,12 +1535,21 @@ impl<'a, K, V> FusedIterator for Iter<'a, K, V> {} impl<'a, K, V> Iterator for IterMut<'a, K, V> { type Item = (&'a K, &'a mut V); - #[inline] fn next(&mut self) -> Option<(&'a K, &'a mut V)> { self.inner.next() } - #[inline] fn size_hint(&self) -> (usize, Option) { self.inner.size_hint() } + #[inline] + fn next(&mut self) -> Option<(&'a K, &'a mut V)> { + self.inner.next() + } + #[inline] + fn size_hint(&self) -> (usize, Option) { + self.inner.size_hint() + } } #[stable(feature = "rust1", since = "1.0.0")] impl<'a, K, V> ExactSizeIterator for IterMut<'a, K, V> { - #[inline] fn len(&self) -> usize { self.inner.len() } + #[inline] + fn len(&self) -> usize { + self.inner.len() + } } #[unstable(feature = "fused", issue = "35602")] impl<'a, K, V> FusedIterator for IterMut<'a, K, V> {} @@ -1525,12 +1558,21 @@ impl<'a, K, V> FusedIterator for IterMut<'a, K, V> {} impl Iterator for IntoIter { type Item = (K, V); - #[inline] fn next(&mut self) -> Option<(K, V)> { self.inner.next().map(|(_, k, v)| (k, v)) } - #[inline] fn size_hint(&self) -> (usize, Option) { self.inner.size_hint() } + #[inline] + fn next(&mut self) -> Option<(K, V)> { + self.inner.next().map(|(_, k, v)| (k, v)) + } + #[inline] + fn size_hint(&self) -> (usize, Option) { + self.inner.size_hint() + } } #[stable(feature = "rust1", since = "1.0.0")] impl ExactSizeIterator for IntoIter { - #[inline] fn len(&self) -> usize { self.inner.len() } + #[inline] + fn len(&self) -> usize { + self.inner.len() + } } #[unstable(feature = "fused", issue = "35602")] impl FusedIterator for IntoIter {} @@ -1539,12 +1581,21 @@ impl FusedIterator for IntoIter {} impl<'a, K, V> Iterator for Keys<'a, K, V> { type Item = &'a K; - #[inline] fn next(&mut self) -> Option<(&'a K)> { self.inner.next().map(|(k, _)| k) } - #[inline] fn size_hint(&self) -> (usize, Option) { self.inner.size_hint() } + #[inline] + fn next(&mut self) -> Option<(&'a K)> { + self.inner.next().map(|(k, _)| k) + } + #[inline] + fn size_hint(&self) -> (usize, Option) { + self.inner.size_hint() + } } #[stable(feature = "rust1", since = "1.0.0")] impl<'a, K, V> ExactSizeIterator for Keys<'a, K, V> { - #[inline] fn len(&self) -> usize { self.inner.len() } + #[inline] + fn len(&self) -> usize { + self.inner.len() + } } #[unstable(feature = "fused", issue = "35602")] impl<'a, K, V> FusedIterator for Keys<'a, K, V> {} @@ -1553,12 +1604,21 @@ impl<'a, K, V> FusedIterator for Keys<'a, K, V> {} impl<'a, K, V> Iterator for Values<'a, K, V> { type Item = &'a V; - #[inline] fn next(&mut self) -> Option<(&'a V)> { self.inner.next().map(|(_, v)| v) } - #[inline] fn size_hint(&self) -> (usize, Option) { self.inner.size_hint() } + #[inline] + fn next(&mut self) -> Option<(&'a V)> { + self.inner.next().map(|(_, v)| v) + } + #[inline] + fn size_hint(&self) -> (usize, Option) { + self.inner.size_hint() + } } #[stable(feature = "rust1", since = "1.0.0")] impl<'a, K, V> ExactSizeIterator for Values<'a, K, V> { - #[inline] fn len(&self) -> usize { self.inner.len() } + #[inline] + fn len(&self) -> usize { + self.inner.len() + } } #[unstable(feature = "fused", issue = "35602")] impl<'a, K, V> FusedIterator for Values<'a, K, V> {} @@ -1567,26 +1627,44 @@ impl<'a, K, V> FusedIterator for Values<'a, K, V> {} impl<'a, K, V> Iterator for ValuesMut<'a, K, V> { type Item = &'a mut V; - #[inline] fn next(&mut self) -> Option<(&'a mut V)> { self.inner.next().map(|(_, v)| v) } - #[inline] fn size_hint(&self) -> (usize, Option) { self.inner.size_hint() } + #[inline] + fn next(&mut self) -> Option<(&'a mut V)> { + self.inner.next().map(|(_, v)| v) + } + #[inline] + fn size_hint(&self) -> (usize, Option) { + self.inner.size_hint() + } } #[stable(feature = "map_values_mut", since = "1.10.0")] impl<'a, K, V> ExactSizeIterator for ValuesMut<'a, K, V> { - #[inline] fn len(&self) -> usize { self.inner.len() } + #[inline] + fn len(&self) -> usize { + self.inner.len() + } } #[unstable(feature = "fused", issue = "35602")] impl<'a, K, V> FusedIterator for ValuesMut<'a, K, V> {} -#[stable(feature = "rust1", since = "1.0.0")] +#[stable(feature = "drain", since = "1.6.0")] impl<'a, K, V> Iterator for Drain<'a, K, V> { type Item = (K, V); - #[inline] fn next(&mut self) -> Option<(K, V)> { self.inner.next().map(|(_, k, v)| (k, v)) } - #[inline] fn size_hint(&self) -> (usize, Option) { self.inner.size_hint() } + #[inline] + fn next(&mut self) -> Option<(K, V)> { + self.inner.next().map(|(_, k, v)| (k, v)) + } + #[inline] + fn size_hint(&self) -> (usize, Option) { + self.inner.size_hint() + } } -#[stable(feature = "rust1", since = "1.0.0")] +#[stable(feature = "drain", since = "1.6.0")] impl<'a, K, V> ExactSizeIterator for Drain<'a, K, V> { - #[inline] fn len(&self) -> usize { self.inner.len() } + #[inline] + fn len(&self) -> usize { + self.inner.len() + } } #[unstable(feature = "fused", issue = "35602")] impl<'a, K, V> FusedIterator for Drain<'a, K, V> {} @@ -1881,21 +1959,18 @@ impl<'a, K: 'a, V: 'a> VacantEntry<'a, K, V> { #[stable(feature = "rust1", since = "1.0.0")] pub fn insert(self, value: V) -> &'a mut V { match self.elem { - NeqElem(bucket, ib) => { - robin_hood(bucket, ib, self.hash, self.key, value) - } - NoElem(bucket) => { - bucket.put(self.hash, self.key, value).into_mut_refs().1 - } + NeqElem(bucket, ib) => robin_hood(bucket, ib, self.hash, self.key, value), + NoElem(bucket) => bucket.put(self.hash, self.key, value).into_mut_refs().1, } } } #[stable(feature = "rust1", since = "1.0.0")] impl FromIterator<(K, V)> for HashMap - where K: Eq + Hash, S: BuildHasher + Default + where K: Eq + Hash, + S: BuildHasher + Default { - fn from_iter>(iter: T) -> HashMap { + fn from_iter>(iter: T) -> HashMap { let iterator = iter.into_iter(); let lower = iterator.size_hint().0; let mut map = HashMap::with_capacity_and_hasher(lower, Default::default()); @@ -1906,9 +1981,10 @@ impl FromIterator<(K, V)> for HashMap #[stable(feature = "rust1", since = "1.0.0")] impl Extend<(K, V)> for HashMap - where K: Eq + Hash, S: BuildHasher + where K: Eq + Hash, + S: BuildHasher { - fn extend>(&mut self, iter: T) { + fn extend>(&mut self, iter: T) { for (k, v) in iter { self.insert(k, v); } @@ -1917,9 +1993,11 @@ impl Extend<(K, V)> for HashMap #[stable(feature = "hash_extend_copy", since = "1.4.0")] impl<'a, K, V, S> Extend<(&'a K, &'a V)> for HashMap - where K: Eq + Hash + Copy, V: Copy, S: BuildHasher + where K: Eq + Hash + Copy, + V: Copy, + S: BuildHasher { - fn extend>(&mut self, iter: T) { + fn extend>(&mut self, iter: T) { self.extend(iter.into_iter().map(|(&key, &value)| (key, value))); } } @@ -1961,7 +2039,8 @@ impl RandomState { /// let s = RandomState::new(); /// ``` #[inline] - #[allow(deprecated)] // rand + #[allow(deprecated)] + // rand #[stable(feature = "hashmap_build_hasher", since = "1.7.0")] pub fn new() -> RandomState { // Historically this function did not cache keys from the OS and instead @@ -1971,24 +2050,19 @@ impl RandomState { // many hash maps are created on a thread. To solve this performance // trap we cache the first set of randomly generated keys per-thread. // - // In doing this, however, we lose the property that all hash maps have - // nondeterministic iteration order as all of those created on the same - // thread would have the same hash keys. This property has been nice in - // the past as it allows for maximal flexibility in the implementation - // of `HashMap` itself. - // - // The constraint here (if there even is one) is just that maps created - // on the same thread have the same iteration order, and that *may* be - // relied upon even though it is not a documented guarantee at all of - // the `HashMap` type. In any case we've decided that this is reasonable - // for now, so caching keys thread-locally seems fine. - thread_local!(static KEYS: (u64, u64) = { + // Later in #36481 it was discovered that exposing a deterministic + // iteration order allows a form of DOS attack. To counter that we + // increment one of the seeds on every RandomState creation, giving + // every corresponding HashMap a different iteration order. + thread_local!(static KEYS: Cell<(u64, u64)> = { let r = rand::OsRng::new(); let mut r = r.expect("failed to create an OS RNG"); - (r.gen(), r.gen()) + Cell::new((r.gen(), r.gen())) }); - KEYS.with(|&(k0, k1)| { + KEYS.with(|keys| { + let (k0, k1) = keys.get(); + keys.set((k0.wrapping_add(1), k1)); RandomState { k0: k0, k1: k1 } }) } @@ -2049,7 +2123,7 @@ impl Hasher for DefaultHasher { } } -#[stable(feature = "rust1", since = "1.0.0")] +#[stable(feature = "hashmap_build_hasher", since = "1.7.0")] impl Default for RandomState { /// Constructs a new `RandomState`. #[inline] @@ -2059,7 +2133,9 @@ impl Default for RandomState { } impl super::Recover for HashMap - where K: Eq + Hash + Borrow, S: BuildHasher, Q: Eq + Hash + where K: Eq + Hash + Borrow, + S: BuildHasher, + Q: Eq + Hash { type Key = K; @@ -2069,7 +2145,7 @@ impl super::Recover for HashMap fn take(&mut self, key: &Q) -> Option { if self.table.size() == 0 { - return None + return None; } self.search_mut(key).into_occupied_bucket().map(|bucket| pop_internal(bucket).0) @@ -2093,18 +2169,40 @@ impl super::Recover for HashMap #[allow(dead_code)] fn assert_covariance() { - fn map_key<'new>(v: HashMap<&'static str, u8>) -> HashMap<&'new str, u8> { v } - fn map_val<'new>(v: HashMap) -> HashMap { v } - fn iter_key<'a, 'new>(v: Iter<'a, &'static str, u8>) -> Iter<'a, &'new str, u8> { v } - fn iter_val<'a, 'new>(v: Iter<'a, u8, &'static str>) -> Iter<'a, u8, &'new str> { v } - fn into_iter_key<'new>(v: IntoIter<&'static str, u8>) -> IntoIter<&'new str, u8> { v } - fn into_iter_val<'new>(v: IntoIter) -> IntoIter { v } - fn keys_key<'a, 'new>(v: Keys<'a, &'static str, u8>) -> Keys<'a, &'new str, u8> { v } - fn keys_val<'a, 'new>(v: Keys<'a, u8, &'static str>) -> Keys<'a, u8, &'new str> { v } - fn values_key<'a, 'new>(v: Values<'a, &'static str, u8>) -> Values<'a, &'new str, u8> { v } - fn values_val<'a, 'new>(v: Values<'a, u8, &'static str>) -> Values<'a, u8, &'new str> { v } + fn map_key<'new>(v: HashMap<&'static str, u8>) -> HashMap<&'new str, u8> { + v + } + fn map_val<'new>(v: HashMap) -> HashMap { + v + } + fn iter_key<'a, 'new>(v: Iter<'a, &'static str, u8>) -> Iter<'a, &'new str, u8> { + v + } + fn iter_val<'a, 'new>(v: Iter<'a, u8, &'static str>) -> Iter<'a, u8, &'new str> { + v + } + fn into_iter_key<'new>(v: IntoIter<&'static str, u8>) -> IntoIter<&'new str, u8> { + v + } + fn into_iter_val<'new>(v: IntoIter) -> IntoIter { + v + } + fn keys_key<'a, 'new>(v: Keys<'a, &'static str, u8>) -> Keys<'a, &'new str, u8> { + v + } + fn keys_val<'a, 'new>(v: Keys<'a, u8, &'static str>) -> Keys<'a, u8, &'new str> { + v + } + fn values_key<'a, 'new>(v: Values<'a, &'static str, u8>) -> Values<'a, &'new str, u8> { + v + } + fn values_val<'a, 'new>(v: Values<'a, u8, &'static str>) -> Values<'a, u8, &'new str> { + v + } fn drain<'new>(d: Drain<'static, &'static str, &'static str>) - -> Drain<'new, &'new str, &'new str> { d } + -> Drain<'new, &'new str, &'new str> { + d + } } #[cfg(test)] @@ -2116,7 +2214,7 @@ mod test_map { use rand::{thread_rng, Rng}; #[test] - fn test_create_capacities() { + fn test_zero_capacities() { type HM = HashMap; let m = HM::new(); @@ -2127,6 +2225,24 @@ mod test_map { let m = HM::with_hasher(RandomState::new()); assert_eq!(m.capacity(), 0); + + let m = HM::with_capacity(0); + assert_eq!(m.capacity(), 0); + + let m = HM::with_capacity_and_hasher(0, RandomState::new()); + assert_eq!(m.capacity(), 0); + + let mut m = HM::new(); + m.insert(1, 1); + m.insert(2, 2); + m.remove(&1); + m.remove(&2); + m.shrink_to_fit(); + assert_eq!(m.capacity(), 0); + + let mut m = HM::new(); + m.reserve(0); + assert_eq!(m.capacity(), 0); } #[test] @@ -2169,7 +2285,7 @@ mod test_map { #[derive(Hash, PartialEq, Eq)] struct Dropable { - k: usize + k: usize, } impl Dropable { @@ -2213,7 +2329,7 @@ mod test_map { for i in 0..100 { let d1 = Dropable::new(i); - let d2 = Dropable::new(i+100); + let d2 = Dropable::new(i + 100); m.insert(d1, d2); } @@ -2272,7 +2388,7 @@ mod test_map { for i in 0..100 { let d1 = Dropable::new(i); - let d2 = Dropable::new(i+100); + let d2 = Dropable::new(i + 100); hm.insert(d1, d2); } @@ -2300,13 +2416,13 @@ mod test_map { for _ in half.by_ref() {} DROP_VECTOR.with(|v| { - let nk = (0..100).filter(|&i| { - v.borrow()[i] == 1 - }).count(); + let nk = (0..100) + .filter(|&i| v.borrow()[i] == 1) + .count(); - let nv = (0..100).filter(|&i| { - v.borrow()[i+100] == 1 - }).count(); + let nv = (0..100) + .filter(|&i| v.borrow()[i + 100] == 1) + .count(); assert_eq!(nk, 50); assert_eq!(nv, 50); @@ -2363,12 +2479,12 @@ mod test_map { for i in 1..1001 { assert!(m.insert(i, i).is_none()); - for j in 1..i+1 { + for j in 1..i + 1 { let r = m.get(&j); assert_eq!(r, Some(&j)); } - for j in i+1..1001 { + for j in i + 1..1001 { let r = m.get(&j); assert_eq!(r, None); } @@ -2382,11 +2498,11 @@ mod test_map { for i in 1..1001 { assert!(m.remove(&i).is_some()); - for j in 1..i+1 { + for j in 1..i + 1 { assert!(!m.contains_key(&j)); } - for j in i+1..1001 { + for j in i + 1..1001 { assert!(m.contains_key(&j)); } } @@ -2422,7 +2538,8 @@ mod test_map { assert!(m.insert(5, 14).is_none()); let new = 100; match m.get_mut(&5) { - None => panic!(), Some(x) => *x = new + None => panic!(), + Some(x) => *x = new, } assert_eq!(m.get(&5), Some(&new)); } @@ -2541,7 +2658,7 @@ mod test_map { m.insert(1, 2); match m.get(&1) { None => panic!(), - Some(v) => assert_eq!(*v, 2) + Some(v) => assert_eq!(*v, 2), } } @@ -2586,8 +2703,8 @@ mod test_map { assert!(m.is_empty()); let mut i = 0; - let old_cap = m.table.capacity(); - while old_cap == m.table.capacity() { + let old_raw_cap = m.raw_capacity(); + while old_raw_cap == m.raw_capacity() { m.insert(i, i); i += 1; } @@ -2601,47 +2718,47 @@ mod test_map { let mut m = HashMap::new(); assert_eq!(m.len(), 0); - assert_eq!(m.table.capacity(), 0); + assert_eq!(m.raw_capacity(), 0); assert!(m.is_empty()); m.insert(0, 0); m.remove(&0); assert!(m.is_empty()); - let initial_cap = m.table.capacity(); - m.reserve(initial_cap); - let cap = m.table.capacity(); + let initial_raw_cap = m.raw_capacity(); + m.reserve(initial_raw_cap); + let raw_cap = m.raw_capacity(); - assert_eq!(cap, initial_cap * 2); + assert_eq!(raw_cap, initial_raw_cap * 2); let mut i = 0; - for _ in 0..cap * 3 / 4 { + for _ in 0..raw_cap * 3 / 4 { m.insert(i, i); i += 1; } // three quarters full assert_eq!(m.len(), i); - assert_eq!(m.table.capacity(), cap); + assert_eq!(m.raw_capacity(), raw_cap); - for _ in 0..cap / 4 { + for _ in 0..raw_cap / 4 { m.insert(i, i); i += 1; } // half full - let new_cap = m.table.capacity(); - assert_eq!(new_cap, cap * 2); + let new_raw_cap = m.raw_capacity(); + assert_eq!(new_raw_cap, raw_cap * 2); - for _ in 0..cap / 2 - 1 { + for _ in 0..raw_cap / 2 - 1 { i -= 1; m.remove(&i); - assert_eq!(m.table.capacity(), new_cap); + assert_eq!(m.raw_capacity(), new_raw_cap); } // A little more than one quarter full. m.shrink_to_fit(); - assert_eq!(m.table.capacity(), cap); + assert_eq!(m.raw_capacity(), raw_cap); // again, a little more than half full - for _ in 0..cap / 2 - 1 { + for _ in 0..raw_cap / 2 - 1 { i -= 1; m.remove(&i); } @@ -2649,7 +2766,7 @@ mod test_map { assert_eq!(m.len(), i); assert!(!m.is_empty()); - assert_eq!(m.table.capacity(), initial_cap); + assert_eq!(m.raw_capacity(), initial_raw_cap); } #[test] @@ -2704,7 +2821,7 @@ mod test_map { fn test_size_hint() { let xs = [(1, 1), (2, 2), (3, 3), (4, 4), (5, 5), (6, 6)]; - let map: HashMap<_, _> = xs.iter().cloned().collect(); + let map: HashMap<_, _> = xs.iter().cloned().collect(); let mut iter = map.iter(); @@ -2717,7 +2834,7 @@ mod test_map { fn test_iter_len() { let xs = [(1, 1), (2, 2), (3, 3), (4, 4), (5, 5), (6, 6)]; - let map: HashMap<_, _> = xs.iter().cloned().collect(); + let map: HashMap<_, _> = xs.iter().cloned().collect(); let mut iter = map.iter(); @@ -2730,7 +2847,7 @@ mod test_map { fn test_mut_size_hint() { let xs = [(1, 1), (2, 2), (3, 3), (4, 4), (5, 5), (6, 6)]; - let mut map: HashMap<_, _> = xs.iter().cloned().collect(); + let mut map: HashMap<_, _> = xs.iter().cloned().collect(); let mut iter = map.iter_mut(); @@ -2743,7 +2860,7 @@ mod test_map { fn test_iter_mut_len() { let xs = [(1, 1), (2, 2), (3, 3), (4, 4), (5, 5), (6, 6)]; - let mut map: HashMap<_, _> = xs.iter().cloned().collect(); + let mut map: HashMap<_, _> = xs.iter().cloned().collect(); let mut iter = map.iter_mut(); @@ -2776,7 +2893,7 @@ mod test_map { } #[test] - fn test_entry(){ + fn test_entry() { let xs = [(1, 10), (2, 20), (3, 30), (4, 40), (5, 50), (6, 60)]; let mut map: HashMap<_, _> = xs.iter().cloned().collect(); @@ -2850,11 +2967,11 @@ mod test_map { for i in 0..1000 { let x = rng.gen_range(-10, 10); match m.entry(x) { - Vacant(_) => {}, + Vacant(_) => {} Occupied(e) => { println!("{}: remove {}", i, x); e.remove(); - }, + } } check(&m); @@ -2932,7 +3049,7 @@ mod test_map { Vacant(e) => { assert_eq!(key, *e.key()); e.insert(value.clone()); - }, + } } assert_eq!(a.len(), 1); assert_eq!(a[key], value); diff --git a/src/libstd/collections/hash/set.rs b/src/libstd/collections/hash/set.rs index a508954398..1ec7a4a7b6 100644 --- a/src/libstd/collections/hash/set.rs +++ b/src/libstd/collections/hash/set.rs @@ -98,10 +98,24 @@ use super::map::{self, HashMap, Keys, RandomState}; /// println!("{:?}", x); /// } /// ``` +/// +/// HashSet with fixed list of elements can be initialized from an array: +/// +/// ``` +/// use std::collections::HashSet; +/// +/// fn main() { +/// let viking_names: HashSet<&str> = +/// [ "Einar", "Olaf", "Harald" ].iter().cloned().collect(); +/// // use the values stored in the set +/// } +/// ``` + + #[derive(Clone)] #[stable(feature = "rust1", since = "1.0.0")] pub struct HashSet { - map: HashMap + map: HashMap, } impl HashSet { @@ -119,8 +133,10 @@ impl HashSet { HashSet { map: HashMap::new() } } - /// Creates an empty HashSet with space for at least `n` elements in - /// the hash table. + /// Creates an empty `HashSet` with the specified capacity. + /// + /// The hash set will be able to hold at least `capacity` elements without + /// reallocating. If `capacity` is 0, the hash set will not allocate. /// /// # Examples /// @@ -136,7 +152,8 @@ impl HashSet { } impl HashSet - where T: Eq + Hash, S: BuildHasher + where T: Eq + Hash, + S: BuildHasher { /// Creates a new empty hash set which will use the given hasher to hash /// keys. @@ -164,8 +181,11 @@ impl HashSet HashSet { map: HashMap::with_hasher(hasher) } } - /// Creates an empty HashSet with space for at least `capacity` - /// elements in the hash table, using `hasher` to hash the keys. + /// Creates an empty HashSet with with the specified capacity, using + /// `hasher` to hash the keys. + /// + /// The hash set will be able to hold at least `capacity` elements without + /// reallocating. If `capacity` is 0, the hash set will not allocate. /// /// Warning: `hasher` is normally randomly generated, and /// is designed to allow `HashSet`s to be resistant to attacks that @@ -184,8 +204,7 @@ impl HashSet /// ``` #[inline] #[stable(feature = "hashmap_build_hasher", since = "1.7.0")] - pub fn with_capacity_and_hasher(capacity: usize, hasher: S) - -> HashSet { + pub fn with_capacity_and_hasher(capacity: usize, hasher: S) -> HashSet { HashSet { map: HashMap::with_capacity_and_hasher(capacity, hasher) } } @@ -323,8 +342,9 @@ impl HashSet /// assert_eq!(diff1, [1, 4].iter().cloned().collect()); /// ``` #[stable(feature = "rust1", since = "1.0.0")] - pub fn symmetric_difference<'a>(&'a self, other: &'a HashSet) - -> SymmetricDifference<'a, T, S> { + pub fn symmetric_difference<'a>(&'a self, + other: &'a HashSet) + -> SymmetricDifference<'a, T, S> { SymmetricDifference { iter: self.difference(other).chain(other.difference(self)) } } @@ -388,7 +408,9 @@ impl HashSet /// assert_eq!(v.len(), 1); /// ``` #[stable(feature = "rust1", since = "1.0.0")] - pub fn len(&self) -> usize { self.map.len() } + pub fn len(&self) -> usize { + self.map.len() + } /// Returns true if the set contains no elements. /// @@ -403,7 +425,9 @@ impl HashSet /// assert!(!v.is_empty()); /// ``` #[stable(feature = "rust1", since = "1.0.0")] - pub fn is_empty(&self) -> bool { self.map.is_empty() } + pub fn is_empty(&self) -> bool { + self.map.is_empty() + } /// Clears the set, returning all elements in an iterator. #[inline] @@ -425,7 +449,9 @@ impl HashSet /// assert!(v.is_empty()); /// ``` #[stable(feature = "rust1", since = "1.0.0")] - pub fn clear(&mut self) { self.map.clear() } + pub fn clear(&mut self) { + self.map.clear() + } /// Returns `true` if the set contains a value. /// @@ -444,7 +470,8 @@ impl HashSet /// ``` #[stable(feature = "rust1", since = "1.0.0")] pub fn contains(&self, value: &Q) -> bool - where T: Borrow, Q: Hash + Eq + where T: Borrow, + Q: Hash + Eq { self.map.contains_key(value) } @@ -456,7 +483,8 @@ impl HashSet /// the value type. #[stable(feature = "set_recovery", since = "1.9.0")] pub fn get(&self, value: &Q) -> Option<&T> - where T: Borrow, Q: Hash + Eq + where T: Borrow, + Q: Hash + Eq { Recover::get(&self.map, value) } @@ -547,7 +575,9 @@ impl HashSet /// assert_eq!(set.len(), 1); /// ``` #[stable(feature = "rust1", since = "1.0.0")] - pub fn insert(&mut self, value: T) -> bool { self.map.insert(value, ()).is_none() } + pub fn insert(&mut self, value: T) -> bool { + self.map.insert(value, ()).is_none() + } /// Adds a value to the set, replacing the existing value, if any, that is equal to the given /// one. Returns the replaced value. @@ -576,7 +606,8 @@ impl HashSet /// ``` #[stable(feature = "rust1", since = "1.0.0")] pub fn remove(&mut self, value: &Q) -> bool - where T: Borrow, Q: Hash + Eq + where T: Borrow, + Q: Hash + Eq { self.map.remove(value).is_some() } @@ -588,7 +619,8 @@ impl HashSet /// the value type. #[stable(feature = "set_recovery", since = "1.9.0")] pub fn take(&mut self, value: &Q) -> Option - where T: Borrow, Q: Hash + Eq + where T: Borrow, + Q: Hash + Eq { Recover::take(&mut self.map, value) } @@ -596,10 +628,13 @@ impl HashSet #[stable(feature = "rust1", since = "1.0.0")] impl PartialEq for HashSet - where T: Eq + Hash, S: BuildHasher + where T: Eq + Hash, + S: BuildHasher { fn eq(&self, other: &HashSet) -> bool { - if self.len() != other.len() { return false; } + if self.len() != other.len() { + return false; + } self.iter().all(|key| other.contains(key)) } @@ -607,8 +642,10 @@ impl PartialEq for HashSet #[stable(feature = "rust1", since = "1.0.0")] impl Eq for HashSet - where T: Eq + Hash, S: BuildHasher -{} + where T: Eq + Hash, + S: BuildHasher +{ +} #[stable(feature = "rust1", since = "1.0.0")] impl fmt::Debug for HashSet @@ -623,9 +660,9 @@ impl fmt::Debug for HashSet #[stable(feature = "rust1", since = "1.0.0")] impl FromIterator for HashSet where T: Eq + Hash, - S: BuildHasher + Default, + S: BuildHasher + Default { - fn from_iter>(iter: I) -> HashSet { + fn from_iter>(iter: I) -> HashSet { let iterator = iter.into_iter(); let lower = iterator.size_hint().0; let mut set = HashSet::with_capacity_and_hasher(lower, Default::default()); @@ -637,9 +674,9 @@ impl FromIterator for HashSet #[stable(feature = "rust1", since = "1.0.0")] impl Extend for HashSet where T: Eq + Hash, - S: BuildHasher, + S: BuildHasher { - fn extend>(&mut self, iter: I) { + fn extend>(&mut self, iter: I) { for k in iter { self.insert(k); } @@ -649,9 +686,9 @@ impl Extend for HashSet #[stable(feature = "hash_extend_copy", since = "1.4.0")] impl<'a, T, S> Extend<&'a T> for HashSet where T: 'a + Eq + Hash + Copy, - S: BuildHasher, + S: BuildHasher { - fn extend>(&mut self, iter: I) { + fn extend>(&mut self, iter: I) { self.extend(iter.into_iter().cloned()); } } @@ -659,7 +696,7 @@ impl<'a, T, S> Extend<&'a T> for HashSet #[stable(feature = "rust1", since = "1.0.0")] impl Default for HashSet where T: Eq + Hash, - S: BuildHasher + Default, + S: BuildHasher + Default { /// Creates an empty `HashSet` with the `Default` value for the hasher. fn default() -> HashSet { @@ -670,7 +707,7 @@ impl Default for HashSet #[stable(feature = "rust1", since = "1.0.0")] impl<'a, 'b, T, S> BitOr<&'b HashSet> for &'a HashSet where T: Eq + Hash + Clone, - S: BuildHasher + Default, + S: BuildHasher + Default { type Output = HashSet; @@ -702,7 +739,7 @@ impl<'a, 'b, T, S> BitOr<&'b HashSet> for &'a HashSet #[stable(feature = "rust1", since = "1.0.0")] impl<'a, 'b, T, S> BitAnd<&'b HashSet> for &'a HashSet where T: Eq + Hash + Clone, - S: BuildHasher + Default, + S: BuildHasher + Default { type Output = HashSet; @@ -734,7 +771,7 @@ impl<'a, 'b, T, S> BitAnd<&'b HashSet> for &'a HashSet #[stable(feature = "rust1", since = "1.0.0")] impl<'a, 'b, T, S> BitXor<&'b HashSet> for &'a HashSet where T: Eq + Hash + Clone, - S: BuildHasher + Default, + S: BuildHasher + Default { type Output = HashSet; @@ -766,7 +803,7 @@ impl<'a, 'b, T, S> BitXor<&'b HashSet> for &'a HashSet #[stable(feature = "rust1", since = "1.0.0")] impl<'a, 'b, T, S> Sub<&'b HashSet> for &'a HashSet where T: Eq + Hash + Clone, - S: BuildHasher + Default, + S: BuildHasher + Default { type Output = HashSet; @@ -798,13 +835,13 @@ impl<'a, 'b, T, S> Sub<&'b HashSet> for &'a HashSet /// HashSet iterator #[stable(feature = "rust1", since = "1.0.0")] pub struct Iter<'a, K: 'a> { - iter: Keys<'a, K, ()> + iter: Keys<'a, K, ()>, } /// HashSet move iterator #[stable(feature = "rust1", since = "1.0.0")] pub struct IntoIter { - iter: map::IntoIter + iter: map::IntoIter, } /// HashSet drain iterator @@ -834,18 +871,19 @@ pub struct Difference<'a, T: 'a, S: 'a> { /// Symmetric difference iterator. #[stable(feature = "rust1", since = "1.0.0")] pub struct SymmetricDifference<'a, T: 'a, S: 'a> { - iter: Chain, Difference<'a, T, S>> + iter: Chain, Difference<'a, T, S>>, } /// Set union iterator. #[stable(feature = "rust1", since = "1.0.0")] pub struct Union<'a, T: 'a, S: 'a> { - iter: Chain, Difference<'a, T, S>> + iter: Chain, Difference<'a, T, S>>, } #[stable(feature = "rust1", since = "1.0.0")] impl<'a, T, S> IntoIterator for &'a HashSet - where T: Eq + Hash, S: BuildHasher + where T: Eq + Hash, + S: BuildHasher { type Item = &'a T; type IntoIter = Iter<'a, T>; @@ -890,18 +928,26 @@ impl IntoIterator for HashSet #[stable(feature = "rust1", since = "1.0.0")] impl<'a, K> Clone for Iter<'a, K> { - fn clone(&self) -> Iter<'a, K> { Iter { iter: self.iter.clone() } } + fn clone(&self) -> Iter<'a, K> { + Iter { iter: self.iter.clone() } + } } #[stable(feature = "rust1", since = "1.0.0")] impl<'a, K> Iterator for Iter<'a, K> { type Item = &'a K; - fn next(&mut self) -> Option<&'a K> { self.iter.next() } - fn size_hint(&self) -> (usize, Option) { self.iter.size_hint() } + fn next(&mut self) -> Option<&'a K> { + self.iter.next() + } + fn size_hint(&self) -> (usize, Option) { + self.iter.size_hint() + } } #[stable(feature = "rust1", since = "1.0.0")] impl<'a, K> ExactSizeIterator for Iter<'a, K> { - fn len(&self) -> usize { self.iter.len() } + fn len(&self) -> usize { + self.iter.len() + } } #[unstable(feature = "fused", issue = "35602")] impl<'a, K> FusedIterator for Iter<'a, K> {} @@ -910,12 +956,18 @@ impl<'a, K> FusedIterator for Iter<'a, K> {} impl Iterator for IntoIter { type Item = K; - fn next(&mut self) -> Option { self.iter.next().map(|(k, _)| k) } - fn size_hint(&self) -> (usize, Option) { self.iter.size_hint() } + fn next(&mut self) -> Option { + self.iter.next().map(|(k, _)| k) + } + fn size_hint(&self) -> (usize, Option) { + self.iter.size_hint() + } } #[stable(feature = "rust1", since = "1.0.0")] impl ExactSizeIterator for IntoIter { - fn len(&self) -> usize { self.iter.len() } + fn len(&self) -> usize { + self.iter.len() + } } #[unstable(feature = "fused", issue = "35602")] impl FusedIterator for IntoIter {} @@ -924,12 +976,18 @@ impl FusedIterator for IntoIter {} impl<'a, K> Iterator for Drain<'a, K> { type Item = K; - fn next(&mut self) -> Option { self.iter.next().map(|(k, _)| k) } - fn size_hint(&self) -> (usize, Option) { self.iter.size_hint() } + fn next(&mut self) -> Option { + self.iter.next().map(|(k, _)| k) + } + fn size_hint(&self) -> (usize, Option) { + self.iter.size_hint() + } } #[stable(feature = "rust1", since = "1.0.0")] impl<'a, K> ExactSizeIterator for Drain<'a, K> { - fn len(&self) -> usize { self.iter.len() } + fn len(&self) -> usize { + self.iter.len() + } } #[unstable(feature = "fused", issue = "35602")] impl<'a, K> FusedIterator for Drain<'a, K> {} @@ -943,7 +1001,8 @@ impl<'a, T, S> Clone for Intersection<'a, T, S> { #[stable(feature = "rust1", since = "1.0.0")] impl<'a, T, S> Iterator for Intersection<'a, T, S> - where T: Eq + Hash, S: BuildHasher + where T: Eq + Hash, + S: BuildHasher { type Item = &'a T; @@ -951,9 +1010,11 @@ impl<'a, T, S> Iterator for Intersection<'a, T, S> loop { match self.iter.next() { None => return None, - Some(elt) => if self.other.contains(elt) { - return Some(elt) - }, + Some(elt) => { + if self.other.contains(elt) { + return Some(elt); + } + } } } } @@ -966,8 +1027,10 @@ impl<'a, T, S> Iterator for Intersection<'a, T, S> #[unstable(feature = "fused", issue = "35602")] impl<'a, T, S> FusedIterator for Intersection<'a, T, S> - where T: Eq + Hash, S: BuildHasher -{} + where T: Eq + Hash, + S: BuildHasher +{ +} #[stable(feature = "rust1", since = "1.0.0")] impl<'a, T, S> Clone for Difference<'a, T, S> { @@ -978,7 +1041,8 @@ impl<'a, T, S> Clone for Difference<'a, T, S> { #[stable(feature = "rust1", since = "1.0.0")] impl<'a, T, S> Iterator for Difference<'a, T, S> - where T: Eq + Hash, S: BuildHasher + where T: Eq + Hash, + S: BuildHasher { type Item = &'a T; @@ -986,9 +1050,11 @@ impl<'a, T, S> Iterator for Difference<'a, T, S> loop { match self.iter.next() { None => return None, - Some(elt) => if !self.other.contains(elt) { - return Some(elt) - }, + Some(elt) => { + if !self.other.contains(elt) { + return Some(elt); + } + } } } } @@ -1001,8 +1067,10 @@ impl<'a, T, S> Iterator for Difference<'a, T, S> #[unstable(feature = "fused", issue = "35602")] impl<'a, T, S> FusedIterator for Difference<'a, T, S> - where T: Eq + Hash, S: BuildHasher -{} + where T: Eq + Hash, + S: BuildHasher +{ +} #[stable(feature = "rust1", since = "1.0.0")] impl<'a, T, S> Clone for SymmetricDifference<'a, T, S> { @@ -1013,53 +1081,85 @@ impl<'a, T, S> Clone for SymmetricDifference<'a, T, S> { #[stable(feature = "rust1", since = "1.0.0")] impl<'a, T, S> Iterator for SymmetricDifference<'a, T, S> - where T: Eq + Hash, S: BuildHasher + where T: Eq + Hash, + S: BuildHasher { type Item = &'a T; - fn next(&mut self) -> Option<&'a T> { self.iter.next() } - fn size_hint(&self) -> (usize, Option) { self.iter.size_hint() } + fn next(&mut self) -> Option<&'a T> { + self.iter.next() + } + fn size_hint(&self) -> (usize, Option) { + self.iter.size_hint() + } } #[unstable(feature = "fused", issue = "35602")] impl<'a, T, S> FusedIterator for SymmetricDifference<'a, T, S> - where T: Eq + Hash, S: BuildHasher -{} + where T: Eq + Hash, + S: BuildHasher +{ +} #[stable(feature = "rust1", since = "1.0.0")] impl<'a, T, S> Clone for Union<'a, T, S> { - fn clone(&self) -> Union<'a, T, S> { Union { iter: self.iter.clone() } } + fn clone(&self) -> Union<'a, T, S> { + Union { iter: self.iter.clone() } + } } #[unstable(feature = "fused", issue = "35602")] impl<'a, T, S> FusedIterator for Union<'a, T, S> - where T: Eq + Hash, S: BuildHasher -{} + where T: Eq + Hash, + S: BuildHasher +{ +} #[stable(feature = "rust1", since = "1.0.0")] impl<'a, T, S> Iterator for Union<'a, T, S> - where T: Eq + Hash, S: BuildHasher + where T: Eq + Hash, + S: BuildHasher { type Item = &'a T; - fn next(&mut self) -> Option<&'a T> { self.iter.next() } - fn size_hint(&self) -> (usize, Option) { self.iter.size_hint() } + fn next(&mut self) -> Option<&'a T> { + self.iter.next() + } + fn size_hint(&self) -> (usize, Option) { + self.iter.size_hint() + } } #[allow(dead_code)] fn assert_covariance() { - fn set<'new>(v: HashSet<&'static str>) -> HashSet<&'new str> { v } - fn iter<'a, 'new>(v: Iter<'a, &'static str>) -> Iter<'a, &'new str> { v } - fn into_iter<'new>(v: IntoIter<&'static str>) -> IntoIter<&'new str> { v } + fn set<'new>(v: HashSet<&'static str>) -> HashSet<&'new str> { + v + } + fn iter<'a, 'new>(v: Iter<'a, &'static str>) -> Iter<'a, &'new str> { + v + } + fn into_iter<'new>(v: IntoIter<&'static str>) -> IntoIter<&'new str> { + v + } fn difference<'a, 'new>(v: Difference<'a, &'static str, RandomState>) - -> Difference<'a, &'new str, RandomState> { v } + -> Difference<'a, &'new str, RandomState> { + v + } fn symmetric_difference<'a, 'new>(v: SymmetricDifference<'a, &'static str, RandomState>) - -> SymmetricDifference<'a, &'new str, RandomState> { v } + -> SymmetricDifference<'a, &'new str, RandomState> { + v + } fn intersection<'a, 'new>(v: Intersection<'a, &'static str, RandomState>) - -> Intersection<'a, &'new str, RandomState> { v } + -> Intersection<'a, &'new str, RandomState> { + v + } fn union<'a, 'new>(v: Union<'a, &'static str, RandomState>) - -> Union<'a, &'new str, RandomState> { v } - fn drain<'new>(d: Drain<'static, &'static str>) -> Drain<'new, &'new str> { d } + -> Union<'a, &'new str, RandomState> { + v + } + fn drain<'new>(d: Drain<'static, &'static str>) -> Drain<'new, &'new str> { + d + } } #[cfg(test)] @@ -1068,7 +1168,7 @@ mod test_set { use super::super::map::RandomState; #[test] - fn test_create_capacities() { + fn test_zero_capacities() { type HS = HashSet; let s = HS::new(); @@ -1079,6 +1179,24 @@ mod test_set { let s = HS::with_hasher(RandomState::new()); assert_eq!(s.capacity(), 0); + + let s = HS::with_capacity(0); + assert_eq!(s.capacity(), 0); + + let s = HS::with_capacity_and_hasher(0, RandomState::new()); + assert_eq!(s.capacity(), 0); + + let mut s = HS::new(); + s.insert(1); + s.insert(2); + s.remove(&1); + s.remove(&2); + s.shrink_to_fit(); + assert_eq!(s.capacity(), 0); + + let mut s = HS::new(); + s.reserve(0); + assert_eq!(s.capacity(), 0); } #[test] @@ -1346,7 +1464,9 @@ mod test_set { assert_eq!(last_i, 49); } - for _ in &s { panic!("s should be empty!"); } + for _ in &s { + panic!("s should be empty!"); + } // reset to try again. s.extend(1..100); diff --git a/src/libstd/collections/hash/table.rs b/src/libstd/collections/hash/table.rs index 8f02c9c7d3..a784d8e50f 100644 --- a/src/libstd/collections/hash/table.rs +++ b/src/libstd/collections/hash/table.rs @@ -21,13 +21,24 @@ use ptr::{self, Unique, Shared}; use self::BucketState::*; -const EMPTY_BUCKET: u64 = 0; +/// Integer type used for stored hash values. +/// +/// No more than bit_width(usize) bits are needed to select a bucket. +/// +/// The most significant bit is ours to use for tagging `SafeHash`. +/// +/// (Even if we could have usize::MAX bytes allocated for buckets, +/// each bucket stores at least a `HashUint`, so there can be no more than +/// usize::MAX / size_of(usize) buckets.) +type HashUint = usize; + +const EMPTY_BUCKET: HashUint = 0; /// The raw hashtable, providing safe-ish access to the unzipped and highly -/// optimized arrays of hashes, keys, and values. +/// optimized arrays of hashes, and key-value pairs. /// -/// This design uses less memory and is a lot faster than the naive -/// `Vec>`, because we don't pay for the overhead of an +/// This design is a lot faster than the naive +/// `Vec>`, because we don't pay for the overhead of an /// option on every element, and we get a generally more cache-aware design. /// /// Essential invariants of this structure: @@ -48,22 +59,23 @@ const EMPTY_BUCKET: u64 = 0; /// which will likely map to the same bucket, while not being confused /// with "empty". /// -/// - All three "arrays represented by pointers" are the same length: +/// - Both "arrays represented by pointers" are the same length: /// `capacity`. This is set at creation and never changes. The arrays -/// are unzipped to save space (we don't have to pay for the padding -/// between odd sized elements, such as in a map from u64 to u8), and -/// be more cache aware (scanning through 8 hashes brings in at most -/// 2 cache lines, since they're all right beside each other). +/// are unzipped and are more cache aware (scanning through 8 hashes +/// brings in at most 2 cache lines, since they're all right beside each +/// other). This layout may waste space in padding such as in a map from +/// u64 to u8, but is a more cache conscious layout as the key-value pairs +/// are only very shortly probed and the desired value will be in the same +/// or next cache line. /// /// You can kind of think of this module/data structure as a safe wrapper /// around just the "table" part of the hashtable. It enforces some /// invariants at the type level and employs some performance trickery, -/// but in general is just a tricked out `Vec>`. -#[cfg_attr(stage0, unsafe_no_drop_flag)] +/// but in general is just a tricked out `Vec>`. pub struct RawTable { capacity: usize, size: usize, - hashes: Unique, + hashes: Unique, // Because K/V do not appear directly in any of the types in the struct, // inform rustc that in fact instances of K and V are reachable from here. @@ -74,11 +86,9 @@ unsafe impl Send for RawTable {} unsafe impl Sync for RawTable {} struct RawBucket { - hash: *mut u64, - + hash: *mut HashUint, // We use *const to ensure covariance with respect to K and V - key: *const K, - val: *const V, + pair: *const (K, V), _marker: marker::PhantomData<(K, V)>, } @@ -114,10 +124,6 @@ pub struct FullBucket { table: M, } -pub type EmptyBucketImm<'table, K, V> = EmptyBucket>; -pub type FullBucketImm<'table, K, V> = FullBucket>; - -pub type EmptyBucketMut<'table, K, V> = EmptyBucket>; pub type FullBucketMut<'table, K, V> = FullBucket>; pub enum BucketState { @@ -137,15 +143,27 @@ pub struct GapThenFull { /// buckets. #[derive(PartialEq, Copy, Clone)] pub struct SafeHash { - hash: u64, + hash: HashUint, } impl SafeHash { /// Peek at the hash value, which is guaranteed to be non-zero. #[inline(always)] - pub fn inspect(&self) -> u64 { + pub fn inspect(&self) -> HashUint { self.hash } + + #[inline(always)] + pub fn new(hash: u64) -> Self { + // We need to avoid 0 in order to prevent collisions with + // EMPTY_HASH. We can maintain our precious uniform distribution + // of initial indexes by unconditionally setting the MSB, + // effectively reducing the hashes by one bit. + // + // Truncate hash to fit in `HashUint`. + let hash_bits = size_of::() * 8; + SafeHash { hash: (1 << (hash_bits - 1)) | (hash as HashUint) } + } } /// We need to remove hashes of 0. That's reserved for empty buckets. @@ -157,33 +175,28 @@ pub fn make_hash(hash_state: &S, t: &T) -> SafeHash { let mut state = hash_state.build_hasher(); t.hash(&mut state); - // We need to avoid 0 in order to prevent collisions with - // EMPTY_HASH. We can maintain our precious uniform distribution - // of initial indexes by unconditionally setting the MSB, - // effectively reducing 64-bits hashes to 63 bits. - SafeHash { hash: 0x8000_0000_0000_0000 | state.finish() } + SafeHash::new(state.finish()) } -// `replace` casts a `*u64` to a `*SafeHash`. Since we statically +// `replace` casts a `*HashUint` to a `*SafeHash`. Since we statically // ensure that a `FullBucket` points to an index with a non-zero hash, -// and a `SafeHash` is just a `u64` with a different name, this is +// and a `SafeHash` is just a `HashUint` with a different name, this is // safe. // // This test ensures that a `SafeHash` really IS the same size as a -// `u64`. If you need to change the size of `SafeHash` (and +// `HashUint`. If you need to change the size of `SafeHash` (and // consequently made this test fail), `replace` needs to be // modified to no longer assume this. #[test] -fn can_alias_safehash_as_u64() { - assert_eq!(size_of::(), size_of::()) +fn can_alias_safehash_as_hash() { + assert_eq!(size_of::(), size_of::()) } impl RawBucket { unsafe fn offset(self, count: isize) -> RawBucket { RawBucket { hash: self.hash.offset(count), - key: self.key.offset(count), - val: self.val.offset(count), + pair: self.pair.offset(count), _marker: marker::PhantomData, } } @@ -371,8 +384,7 @@ impl EmptyBucket pub fn put(mut self, hash: SafeHash, key: K, value: V) -> FullBucket { unsafe { *self.raw.hash = hash.inspect(); - ptr::write(self.raw.key as *mut K, key); - ptr::write(self.raw.val as *mut V, value); + ptr::write(self.raw.pair as *mut (K, V), (key, value)); self.table.borrow_table_mut().size += 1; } @@ -431,7 +443,7 @@ impl>> FullBucket { /// Gets references to the key and value at a given index. pub fn read(&self) -> (&K, &V) { - unsafe { (&*self.raw.key, &*self.raw.val) } + unsafe { (&(*self.raw.pair).0, &(*self.raw.pair).1) } } } @@ -448,13 +460,14 @@ impl<'t, K, V> FullBucket> { unsafe { *self.raw.hash = EMPTY_BUCKET; + let (k, v) = ptr::read(self.raw.pair); (EmptyBucket { - raw: self.raw, - idx: self.idx, - table: self.table, - }, - ptr::read(self.raw.key), - ptr::read(self.raw.val)) + raw: self.raw, + idx: self.idx, + table: self.table, + }, + k, + v) } } } @@ -467,8 +480,7 @@ impl FullBucket pub fn replace(&mut self, h: SafeHash, k: K, v: V) -> (SafeHash, K, V) { unsafe { let old_hash = ptr::replace(self.raw.hash as *mut SafeHash, h); - let old_key = ptr::replace(self.raw.key as *mut K, k); - let old_val = ptr::replace(self.raw.val as *mut V, v); + let (old_key, old_val) = ptr::replace(self.raw.pair as *mut (K, V), (k, v)); (old_hash, old_key, old_val) } @@ -480,7 +492,8 @@ impl FullBucket { /// Gets mutable references to the key and value at a given index. pub fn read_mut(&mut self) -> (&mut K, &mut V) { - unsafe { (&mut *(self.raw.key as *mut K), &mut *(self.raw.val as *mut V)) } + let pair_mut = self.raw.pair as *mut (K, V); + unsafe { (&mut (*pair_mut).0, &mut (*pair_mut).1) } } } @@ -493,7 +506,7 @@ impl<'t, K, V, M> FullBucket /// in exchange for this, the returned references have a longer lifetime /// than the references returned by `read()`. pub fn into_refs(self) -> (&'t K, &'t V) { - unsafe { (&*self.raw.key, &*self.raw.val) } + unsafe { (&(*self.raw.pair).0, &(*self.raw.pair).1) } } } @@ -503,7 +516,8 @@ impl<'t, K, V, M> FullBucket /// This works similarly to `into_refs`, exchanging a bucket state /// for mutable references into the table. pub fn into_mut_refs(self) -> (&'t mut K, &'t mut V) { - unsafe { (&mut *(self.raw.key as *mut K), &mut *(self.raw.val as *mut V)) } + let pair_mut = self.raw.pair as *mut (K, V); + unsafe { (&mut (*pair_mut).0, &mut (*pair_mut).1) } } } @@ -518,8 +532,7 @@ impl GapThenFull pub fn shift(mut self) -> Option> { unsafe { *self.gap.raw.hash = mem::replace(&mut *self.full.raw.hash, EMPTY_BUCKET); - ptr::copy_nonoverlapping(self.full.raw.key, self.gap.raw.key as *mut K, 1); - ptr::copy_nonoverlapping(self.full.raw.val, self.gap.raw.val as *mut V, 1); + ptr::copy_nonoverlapping(self.full.raw.pair, self.gap.raw.pair as *mut (K, V), 1); } let FullBucket { raw: prev_raw, idx: prev_idx, .. } = self.full; @@ -561,49 +574,42 @@ fn test_rounding() { assert_eq!(round_up_to_next(5, 4), 8); } -// Returns a tuple of (key_offset, val_offset), +// Returns a tuple of (pairs_offset, end_of_pairs_offset), // from the start of a mallocated array. #[inline] fn calculate_offsets(hashes_size: usize, - keys_size: usize, - keys_align: usize, - vals_align: usize) + pairs_size: usize, + pairs_align: usize) -> (usize, usize, bool) { - let keys_offset = round_up_to_next(hashes_size, keys_align); - let (end_of_keys, oflo) = keys_offset.overflowing_add(keys_size); - - let vals_offset = round_up_to_next(end_of_keys, vals_align); + let pairs_offset = round_up_to_next(hashes_size, pairs_align); + let (end_of_pairs, oflo) = pairs_offset.overflowing_add(pairs_size); - (keys_offset, vals_offset, oflo) + (pairs_offset, end_of_pairs, oflo) } // Returns a tuple of (minimum required malloc alignment, hash_offset, // array_size), from the start of a mallocated array. fn calculate_allocation(hash_size: usize, hash_align: usize, - keys_size: usize, - keys_align: usize, - vals_size: usize, - vals_align: usize) + pairs_size: usize, + pairs_align: usize) -> (usize, usize, usize, bool) { let hash_offset = 0; - let (_, vals_offset, oflo) = calculate_offsets(hash_size, keys_size, keys_align, vals_align); - let (end_of_vals, oflo2) = vals_offset.overflowing_add(vals_size); + let (_, end_of_pairs, oflo) = calculate_offsets(hash_size, pairs_size, pairs_align); - let align = cmp::max(hash_align, cmp::max(keys_align, vals_align)); + let align = cmp::max(hash_align, pairs_align); - (align, hash_offset, end_of_vals, oflo || oflo2) + (align, hash_offset, end_of_pairs, oflo) } #[test] fn test_offset_calculation() { - assert_eq!(calculate_allocation(128, 8, 15, 1, 4, 4), - (8, 0, 148, false)); - assert_eq!(calculate_allocation(3, 1, 2, 1, 1, 1), (1, 0, 6, false)); - assert_eq!(calculate_allocation(6, 2, 12, 4, 24, 8), (8, 0, 48, false)); - assert_eq!(calculate_offsets(128, 15, 1, 4), (128, 144, false)); - assert_eq!(calculate_offsets(3, 2, 1, 1), (3, 5, false)); - assert_eq!(calculate_offsets(6, 12, 4, 8), (8, 24, false)); + assert_eq!(calculate_allocation(128, 8, 16, 8), (8, 0, 144, false)); + assert_eq!(calculate_allocation(3, 1, 2, 1), (1, 0, 5, false)); + assert_eq!(calculate_allocation(6, 2, 12, 4), (4, 0, 20, false)); + assert_eq!(calculate_offsets(128, 15, 4), (128, 143, false)); + assert_eq!(calculate_offsets(3, 2, 4), (4, 6, false)); + assert_eq!(calculate_offsets(6, 12, 4), (8, 20, false)); } impl RawTable { @@ -614,18 +620,17 @@ impl RawTable { return RawTable { size: 0, capacity: 0, - hashes: Unique::new(EMPTY as *mut u64), + hashes: Unique::new(EMPTY as *mut HashUint), marker: marker::PhantomData, }; } // No need for `checked_mul` before a more restrictive check performed // later in this method. - let hashes_size = capacity * size_of::(); - let keys_size = capacity * size_of::(); - let vals_size = capacity * size_of::(); + let hashes_size = capacity.wrapping_mul(size_of::()); + let pairs_size = capacity.wrapping_mul(size_of::<(K, V)>()); - // Allocating hashmaps is a little tricky. We need to allocate three + // Allocating hashmaps is a little tricky. We need to allocate two // arrays, but since we know their sizes and alignments up front, // we just allocate a single array, and then have the subarrays // point into it. @@ -633,32 +638,25 @@ impl RawTable { // This is great in theory, but in practice getting the alignment // right is a little subtle. Therefore, calculating offsets has been // factored out into a different function. - let (malloc_alignment, hash_offset, size, oflo) = calculate_allocation(hashes_size, - align_of::(), - keys_size, - align_of::(), - vals_size, - align_of::()); - + let (alignment, hash_offset, size, oflo) = calculate_allocation(hashes_size, + align_of::(), + pairs_size, + align_of::<(K, V)>()); assert!(!oflo, "capacity overflow"); // One check for overflow that covers calculation and rounding of size. - let size_of_bucket = size_of::() - .checked_add(size_of::()) - .unwrap() - .checked_add(size_of::()) - .unwrap(); + let size_of_bucket = size_of::().checked_add(size_of::<(K, V)>()).unwrap(); assert!(size >= capacity.checked_mul(size_of_bucket) - .expect("capacity overflow"), + .expect("capacity overflow"), "capacity overflow"); - let buffer = allocate(size, malloc_alignment); + let buffer = allocate(size, alignment); if buffer.is_null() { ::alloc::oom() } - let hashes = buffer.offset(hash_offset as isize) as *mut u64; + let hashes = buffer.offset(hash_offset as isize) as *mut HashUint; RawTable { capacity: capacity, @@ -669,20 +667,17 @@ impl RawTable { } fn first_bucket_raw(&self) -> RawBucket { - let hashes_size = self.capacity * size_of::(); - let keys_size = self.capacity * size_of::(); - - let buffer = *self.hashes as *const u8; - let (keys_offset, vals_offset, oflo) = calculate_offsets(hashes_size, - keys_size, - align_of::(), - align_of::()); + let hashes_size = self.capacity * size_of::(); + let pairs_size = self.capacity * size_of::<(K, V)>(); + + let buffer = *self.hashes as *mut u8; + let (pairs_offset, _, oflo) = + calculate_offsets(hashes_size, pairs_size, align_of::<(K, V)>()); debug_assert!(!oflo, "capacity overflow"); unsafe { RawBucket { hash: *self.hashes, - key: buffer.offset(keys_offset as isize) as *const K, - val: buffer.offset(vals_offset as isize) as *const V, + pair: buffer.offset(pairs_offset as isize) as *const _, _marker: marker::PhantomData, } } @@ -776,7 +771,7 @@ impl RawTable { /// this interface is safe, it's not used outside this module. struct RawBuckets<'a, K, V> { raw: RawBucket, - hashes_end: *mut u64, + hashes_end: *mut HashUint, // Strictly speaking, this should be &'a (K,V), but that would // require that K:'a, and we often use RawBuckets<'static...> for @@ -822,7 +817,7 @@ impl<'a, K, V> Iterator for RawBuckets<'a, K, V> { /// the table's remaining entries. It's used in the implementation of Drop. struct RevMoveBuckets<'a, K, V> { raw: RawBucket, - hashes_end: *mut u64, + hashes_end: *mut HashUint, elems_left: usize, // As above, `&'a (K,V)` would seem better, but we often use @@ -847,7 +842,7 @@ impl<'a, K, V> Iterator for RevMoveBuckets<'a, K, V> { if *self.raw.hash != EMPTY_BUCKET { self.elems_left -= 1; - return Some((ptr::read(self.raw.key), ptr::read(self.raw.val))); + return Some(ptr::read(self.raw.pair)); } } } @@ -912,7 +907,7 @@ impl<'a, K, V> Iterator for Iter<'a, K, V> { fn next(&mut self) -> Option<(&'a K, &'a V)> { self.iter.next().map(|bucket| { self.elems_left -= 1; - unsafe { (&*bucket.key, &*bucket.val) } + unsafe { (&(*bucket.pair).0, &(*bucket.pair).1) } }) } @@ -932,7 +927,8 @@ impl<'a, K, V> Iterator for IterMut<'a, K, V> { fn next(&mut self) -> Option<(&'a K, &'a mut V)> { self.iter.next().map(|bucket| { self.elems_left -= 1; - unsafe { (&*bucket.key, &mut *(bucket.val as *mut V)) } + let pair_mut = bucket.pair as *mut (K, V); + unsafe { (&(*pair_mut).0, &mut (*pair_mut).1) } }) } @@ -953,7 +949,8 @@ impl Iterator for IntoIter { self.iter.next().map(|bucket| { self.table.size -= 1; unsafe { - (SafeHash { hash: *bucket.hash }, ptr::read(bucket.key), ptr::read(bucket.val)) + let (k, v) = ptr::read(bucket.pair); + (SafeHash { hash: *bucket.hash }, k, v) } }) } @@ -977,9 +974,8 @@ impl<'a, K, V> Iterator for Drain<'a, K, V> { self.iter.next().map(|bucket| { unsafe { (**self.table).size -= 1; - (SafeHash { hash: ptr::replace(bucket.hash, EMPTY_BUCKET) }, - ptr::read(bucket.key), - ptr::read(bucket.val)) + let (k, v) = ptr::read(bucket.pair); + (SafeHash { hash: ptr::replace(bucket.hash, EMPTY_BUCKET) }, k, v) } }) } @@ -991,9 +987,7 @@ impl<'a, K, V> Iterator for Drain<'a, K, V> { } impl<'a, K, V> ExactSizeIterator for Drain<'a, K, V> { fn len(&self) -> usize { - unsafe { - (**self.table).size() - } + unsafe { (**self.table).size() } } } @@ -1020,8 +1014,7 @@ impl Clone for RawTable { (full.hash(), k.clone(), v.clone()) }; *new_buckets.raw.hash = h.inspect(); - ptr::write(new_buckets.raw.key as *mut K, k); - ptr::write(new_buckets.raw.val as *mut V, v); + ptr::write(new_buckets.raw.pair as *mut (K, V), (k, v)); } Empty(..) => { *new_buckets.raw.hash = EMPTY_BUCKET; @@ -1058,15 +1051,12 @@ impl Drop for RawTable { } } - let hashes_size = self.capacity * size_of::(); - let keys_size = self.capacity * size_of::(); - let vals_size = self.capacity * size_of::(); + let hashes_size = self.capacity * size_of::(); + let pairs_size = self.capacity * size_of::<(K, V)>(); let (align, _, size, oflo) = calculate_allocation(hashes_size, - align_of::(), - keys_size, - align_of::(), - vals_size, - align_of::()); + align_of::(), + pairs_size, + align_of::<(K, V)>()); debug_assert!(!oflo, "should be impossible"); diff --git a/src/libstd/collections/mod.rs b/src/libstd/collections/mod.rs index 9b13d54230..b9e92a01b2 100644 --- a/src/libstd/collections/mod.rs +++ b/src/libstd/collections/mod.rs @@ -15,7 +15,7 @@ //! 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`. +//! 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 @@ -25,10 +25,10 @@ //! //! Rust's collections can be grouped into four major categories: //! -//! * Sequences: `Vec`, `VecDeque`, `LinkedList` -//! * Maps: `HashMap`, `BTreeMap` -//! * Sets: `HashSet`, `BTreeSet` -//! * Misc: `BinaryHeap` +//! * Sequences: [`Vec`], [`VecDeque`], [`LinkedList`] +//! * Maps: [`HashMap`], [`BTreeMap`] +//! * Sets: [`HashSet`], [`BTreeSet`] +//! * Misc: [`BinaryHeap`] //! //! # When Should You Use Which Collection? //! @@ -46,13 +46,13 @@ //! * You want a heap-allocated array. //! //! ### Use a `VecDeque` when: -//! * You want a `Vec` that supports efficient insertion at both ends of the +//! * 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 +//! * 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 @@ -92,38 +92,38 @@ //! 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* +//! *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 +//! 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 +//! 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 //! -//! | | get(i) | insert(i) | remove(i) | append | split_off(i) | -//! |--------------|----------------|-----------------|----------------|--------|----------------| -//! | Vec | O(1) | O(n-i)* | O(n-i) | O(m)* | O(n-i) | -//! | VecDeque | O(1) | O(min(i, n-i))* | O(min(i, n-i)) | O(m)* | O(min(i, n-i)) | -//! | LinkedList | O(min(i, n-i)) | O(min(i, n-i)) | O(min(i, n-i)) | O(1) | O(min(i, n-i)) | +//! | | get(i) | insert(i) | remove(i) | append | split_off(i) | +//! |----------------|----------------|-----------------|----------------|--------|----------------| +//! | [`Vec`] | O(1) | O(n-i)* | O(n-i) | O(m)* | O(n-i) | +//! | [`VecDeque`] | O(1) | O(min(i, n-i))* | O(min(i, n-i)) | O(m)* | O(min(i, n-i)) | +//! | [`LinkedList`] | O(min(i, n-i)) | O(min(i, n-i)) | O(min(i, n-i)) | O(1) | O(min(i, n-i)) | //! -//! Note that where ties occur, Vec is generally going to be faster than VecDeque, and VecDeque -//! is generally going to be faster than LinkedList. +//! Note that where ties occur, [`Vec`] is generally going to be faster than [`VecDeque`], and +//! [`VecDeque`] is generally going to be faster than [`LinkedList`]. //! //! ## Maps //! //! For Sets, all operations have the cost of the equivalent Map operation. //! -//! | | get | insert | remove | predecessor | append | -//! |----------|-----------|----------|----------|-------------|--------| -//! | HashMap | O(1)~ | O(1)~* | O(1)~ | N/A | N/A | -//! | BTreeMap | O(log n) | O(log n) | O(log n) | O(log n) | O(n+m) | +//! | | get | insert | remove | predecessor | append | +//! |--------------|-----------|----------|----------|-------------|--------| +//! | [`HashMap`] | O(1)~ | O(1)~* | O(1)~ | N/A | N/A | +//! | [`BTreeMap`] | O(log n) | O(log n) | O(log n) | O(log n) | O(n+m) | //! //! # Correct and Efficient Usage of Collections //! @@ -136,7 +136,7 @@ //! ## Capacity Management //! //! Many collections provide several constructors and methods that refer to -//! "capacity". These collections are generally built on top of an array. +//! "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 @@ -157,29 +157,29 @@ //! 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 +//! 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 +//! 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 +//! 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 +//! 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 +//! 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. +//! 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 //! @@ -194,15 +194,15 @@ //! //! 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`. +//! 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`, +//! `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`, +//! 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. @@ -214,8 +214,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]; @@ -224,12 +224,12 @@ //! } //! ``` //! -//! `into_iter` transforms the actual collection into an iterator over its +//! `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` +//! 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. -//! `extend` automatically calls `into_iter`, and takes any `T: IntoIterator`. -//! Calling `collect` on an iterator itself is also a great way to convert one +//! `extend()` automatically calls `into_iter()`, and takes any `T: `[`IntoIterator`]. +//! 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. @@ -248,9 +248,9 @@ //! ``` //! //! Iterators also provide a series of *adapter* methods for performing common -//! threads 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 +//! threads 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. //! @@ -263,27 +263,27 @@ //! //! 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 +//! 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 +//! 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`, +//! 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 +//! 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 value that was inserted. This allows for further manipulation of the //! value beyond the lifetime of the search itself. This is useful if complex @@ -291,14 +291,14 @@ //! 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 +//! 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. +//! vacant `insert()` case. //! //! ### Examples //! -//! Here are the two primary ways in which `entry` is used. First, a simple +//! 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 @@ -322,7 +322,7 @@ //! ``` //! //! 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 +//! use the `entry()` API to ensure that the value is initialized and perform the //! logic afterwards. //! //! #### Tracking the inebriation of customers at a bar @@ -406,6 +406,16 @@ //! // ...but the key hasn't changed. b is still "baz", not "xyz". //! assert_eq!(map.keys().next().unwrap().b, "baz"); //! ``` +//! +//! [`Vec`]: ../../std/vec/struct.Vec.html +//! [`HashMap`]: ../../std/collections/struct.HashMap.html +//! [`VecDeque`]: ../../std/collections/struct.VecDeque.html +//! [`LinkedList`]: ../../std/collections/struct.LinkedList.html +//! [`BTreeMap`]: ../../std/collections/struct.BTreeMap.html +//! [`HashSet`]: ../../std/collections/struct.HashSet.html +//! [`BTreeSet`]: ../../std/collections/struct.BTreeSet.html +//! [`BinaryHeap`]: ../../std/collections/struct.BinaryHeap.html +//! [`IntoIterator`]: ../../std/iter/trait.IntoIterator.html #![stable(feature = "rust1", since = "1.0.0")] @@ -425,6 +435,9 @@ pub use self::hash_map::HashMap; #[stable(feature = "rust1", since = "1.0.0")] pub use self::hash_set::HashSet; +#[stable(feature = "rust1", since = "1.0.0")] +pub use core_collections::range; + mod hash; #[stable(feature = "rust1", since = "1.0.0")] diff --git a/src/libstd/env.rs b/src/libstd/env.rs index 5171fbdf03..e29dbe35c5 100644 --- a/src/libstd/env.rs +++ b/src/libstd/env.rs @@ -21,6 +21,7 @@ use ffi::{OsStr, OsString}; use fmt; use io; use path::{Path, PathBuf}; +use sys; use sys::os as os_imp; /// Returns the current working directory as a `PathBuf`. @@ -557,7 +558,7 @@ pub struct Args { inner: ArgsOs } /// /// This structure is created through the `std::env::args_os` method. #[stable(feature = "env", since = "1.0.0")] -pub struct ArgsOs { inner: os_imp::Args } +pub struct ArgsOs { inner: sys::args::Args } /// Returns the arguments which this program was started with (normally passed /// via the command line). @@ -606,7 +607,7 @@ pub fn args() -> Args { /// ``` #[stable(feature = "env", since = "1.0.0")] pub fn args_os() -> ArgsOs { - ArgsOs { inner: os_imp::args() } + ArgsOs { inner: sys::args::args() } } #[stable(feature = "env", since = "1.0.0")] @@ -649,6 +650,8 @@ impl DoubleEndedIterator for ArgsOs { /// Constants associated with the current target #[stable(feature = "env", since = "1.0.0")] pub mod consts { + use sys::env::os; + /// A string describing the architecture of the CPU that is currently /// in use. /// @@ -673,7 +676,7 @@ pub mod consts { /// - unix /// - windows #[stable(feature = "env", since = "1.0.0")] - pub const FAMILY: &'static str = super::os::FAMILY; + pub const FAMILY: &'static str = os::FAMILY; /// A string describing the specific operating system in use. /// Example value is `linux`. @@ -692,7 +695,7 @@ pub mod consts { /// - android /// - windows #[stable(feature = "env", since = "1.0.0")] - pub const OS: &'static str = super::os::OS; + pub const OS: &'static str = os::OS; /// Specifies the filename prefix used for shared libraries on this /// platform. Example value is `lib`. @@ -702,7 +705,7 @@ pub mod consts { /// - lib /// - `""` (an empty string) #[stable(feature = "env", since = "1.0.0")] - pub const DLL_PREFIX: &'static str = super::os::DLL_PREFIX; + pub const DLL_PREFIX: &'static str = os::DLL_PREFIX; /// Specifies the filename suffix used for shared libraries on this /// platform. Example value is `.so`. @@ -713,7 +716,7 @@ pub mod consts { /// - .dylib /// - .dll #[stable(feature = "env", since = "1.0.0")] - pub const DLL_SUFFIX: &'static str = super::os::DLL_SUFFIX; + pub const DLL_SUFFIX: &'static str = os::DLL_SUFFIX; /// Specifies the file extension used for shared libraries on this /// platform that goes after the dot. Example value is `so`. @@ -724,7 +727,7 @@ pub mod consts { /// - dylib /// - dll #[stable(feature = "env", since = "1.0.0")] - pub const DLL_EXTENSION: &'static str = super::os::DLL_EXTENSION; + pub const DLL_EXTENSION: &'static str = os::DLL_EXTENSION; /// Specifies the filename suffix used for executable binaries on this /// platform. Example value is `.exe`. @@ -736,7 +739,7 @@ pub mod consts { /// - .pexe /// - `""` (an empty string) #[stable(feature = "env", since = "1.0.0")] - pub const EXE_SUFFIX: &'static str = super::os::EXE_SUFFIX; + pub const EXE_SUFFIX: &'static str = os::EXE_SUFFIX; /// Specifies the file extension, if any, used for executable binaries /// on this platform. Example value is `exe`. @@ -746,172 +749,7 @@ pub mod consts { /// - exe /// - `""` (an empty string) #[stable(feature = "env", since = "1.0.0")] - pub const EXE_EXTENSION: &'static str = super::os::EXE_EXTENSION; - -} - -#[cfg(target_os = "linux")] -mod os { - pub const FAMILY: &'static str = "unix"; - pub const OS: &'static str = "linux"; - pub const DLL_PREFIX: &'static str = "lib"; - pub const DLL_SUFFIX: &'static str = ".so"; - pub const DLL_EXTENSION: &'static str = "so"; - pub const EXE_SUFFIX: &'static str = ""; - pub const EXE_EXTENSION: &'static str = ""; -} - -#[cfg(target_os = "macos")] -mod os { - pub const FAMILY: &'static str = "unix"; - pub const OS: &'static str = "macos"; - pub const DLL_PREFIX: &'static str = "lib"; - pub const DLL_SUFFIX: &'static str = ".dylib"; - pub const DLL_EXTENSION: &'static str = "dylib"; - pub const EXE_SUFFIX: &'static str = ""; - pub const EXE_EXTENSION: &'static str = ""; -} - -#[cfg(target_os = "ios")] -mod os { - pub const FAMILY: &'static str = "unix"; - pub const OS: &'static str = "ios"; - pub const DLL_PREFIX: &'static str = "lib"; - pub const DLL_SUFFIX: &'static str = ".dylib"; - pub const DLL_EXTENSION: &'static str = "dylib"; - pub const EXE_SUFFIX: &'static str = ""; - pub const EXE_EXTENSION: &'static str = ""; -} - -#[cfg(target_os = "freebsd")] -mod os { - pub const FAMILY: &'static str = "unix"; - pub const OS: &'static str = "freebsd"; - pub const DLL_PREFIX: &'static str = "lib"; - pub const DLL_SUFFIX: &'static str = ".so"; - pub const DLL_EXTENSION: &'static str = "so"; - pub const EXE_SUFFIX: &'static str = ""; - pub const EXE_EXTENSION: &'static str = ""; -} - -#[cfg(target_os = "dragonfly")] -mod os { - pub const FAMILY: &'static str = "unix"; - pub const OS: &'static str = "dragonfly"; - pub const DLL_PREFIX: &'static str = "lib"; - pub const DLL_SUFFIX: &'static str = ".so"; - pub const DLL_EXTENSION: &'static str = "so"; - pub const EXE_SUFFIX: &'static str = ""; - pub const EXE_EXTENSION: &'static str = ""; -} - -#[cfg(target_os = "bitrig")] -mod os { - pub const FAMILY: &'static str = "unix"; - pub const OS: &'static str = "bitrig"; - pub const DLL_PREFIX: &'static str = "lib"; - pub const DLL_SUFFIX: &'static str = ".so"; - pub const DLL_EXTENSION: &'static str = "so"; - pub const EXE_SUFFIX: &'static str = ""; - pub const EXE_EXTENSION: &'static str = ""; -} - -#[cfg(target_os = "netbsd")] -mod os { - pub const FAMILY: &'static str = "unix"; - pub const OS: &'static str = "netbsd"; - pub const DLL_PREFIX: &'static str = "lib"; - pub const DLL_SUFFIX: &'static str = ".so"; - pub const DLL_EXTENSION: &'static str = "so"; - pub const EXE_SUFFIX: &'static str = ""; - pub const EXE_EXTENSION: &'static str = ""; -} - -#[cfg(target_os = "openbsd")] -mod os { - pub const FAMILY: &'static str = "unix"; - pub const OS: &'static str = "openbsd"; - pub const DLL_PREFIX: &'static str = "lib"; - pub const DLL_SUFFIX: &'static str = ".so"; - pub const DLL_EXTENSION: &'static str = "so"; - pub const EXE_SUFFIX: &'static str = ""; - pub const EXE_EXTENSION: &'static str = ""; -} - -#[cfg(target_os = "android")] -mod os { - pub const FAMILY: &'static str = "unix"; - pub const OS: &'static str = "android"; - pub const DLL_PREFIX: &'static str = "lib"; - pub const DLL_SUFFIX: &'static str = ".so"; - pub const DLL_EXTENSION: &'static str = "so"; - pub const EXE_SUFFIX: &'static str = ""; - pub const EXE_EXTENSION: &'static str = ""; -} - -#[cfg(target_os = "solaris")] -mod os { - pub const FAMILY: &'static str = "unix"; - pub const OS: &'static str = "solaris"; - pub const DLL_PREFIX: &'static str = "lib"; - pub const DLL_SUFFIX: &'static str = ".so"; - pub const DLL_EXTENSION: &'static str = "so"; - pub const EXE_SUFFIX: &'static str = ""; - pub const EXE_EXTENSION: &'static str = ""; -} - -#[cfg(target_os = "windows")] -mod os { - pub const FAMILY: &'static str = "windows"; - pub const OS: &'static str = "windows"; - pub const DLL_PREFIX: &'static str = ""; - pub const DLL_SUFFIX: &'static str = ".dll"; - pub const DLL_EXTENSION: &'static str = "dll"; - pub const EXE_SUFFIX: &'static str = ".exe"; - pub const EXE_EXTENSION: &'static str = "exe"; -} - -#[cfg(all(target_os = "nacl", not(target_arch = "le32")))] -mod os { - pub const FAMILY: &'static str = "unix"; - pub const OS: &'static str = "nacl"; - pub const DLL_PREFIX: &'static str = "lib"; - pub const DLL_SUFFIX: &'static str = ".so"; - pub const DLL_EXTENSION: &'static str = "so"; - pub const EXE_SUFFIX: &'static str = ".nexe"; - pub const EXE_EXTENSION: &'static str = "nexe"; -} -#[cfg(all(target_os = "nacl", target_arch = "le32"))] -mod os { - pub const FAMILY: &'static str = "unix"; - pub const OS: &'static str = "pnacl"; - pub const DLL_PREFIX: &'static str = "lib"; - pub const DLL_SUFFIX: &'static str = ".pso"; - pub const DLL_EXTENSION: &'static str = "pso"; - pub const EXE_SUFFIX: &'static str = ".pexe"; - pub const EXE_EXTENSION: &'static str = "pexe"; -} - -#[cfg(target_os = "emscripten")] -mod os { - pub const FAMILY: &'static str = "unix"; - pub const OS: &'static str = "emscripten"; - pub const DLL_PREFIX: &'static str = "lib"; - pub const DLL_SUFFIX: &'static str = ".so"; - pub const DLL_EXTENSION: &'static str = "so"; - pub const EXE_SUFFIX: &'static str = ".js"; - pub const EXE_EXTENSION: &'static str = "js"; -} - -#[cfg(target_os = "haiku")] -mod os { - pub const FAMILY: &'static str = "unix"; - pub const OS: &'static str = "haiku"; - pub const DLL_PREFIX: &'static str = "lib"; - pub const DLL_SUFFIX: &'static str = ".so"; - pub const DLL_EXTENSION: &'static str = "so"; - pub const EXE_SUFFIX: &'static str = ""; - pub const EXE_EXTENSION: &'static str = ""; + pub const EXE_EXTENSION: &'static str = os::EXE_EXTENSION; } #[cfg(target_arch = "x86")] @@ -969,6 +807,11 @@ mod arch { pub const ARCH: &'static str = "asmjs"; } +#[cfg(target_arch = "wasm32")] +mod arch { + pub const ARCH: &'static str = "wasm32"; +} + #[cfg(test)] mod tests { use super::*; @@ -1017,6 +860,7 @@ mod tests { } #[test] + #[cfg_attr(target_os = "emscripten", ignore)] fn test_var_big() { let mut s = "".to_string(); let mut i = 0; @@ -1030,6 +874,7 @@ mod tests { } #[test] + #[cfg_attr(target_os = "emscripten", ignore)] fn test_self_exe_path() { let path = current_exe(); assert!(path.is_ok()); @@ -1040,6 +885,7 @@ mod tests { } #[test] + #[cfg_attr(target_os = "emscripten", ignore)] fn test_env_set_get_huge() { let n = make_rand_name(); let s = repeat("x").take(10000).collect::(); diff --git a/src/libstd/error.rs b/src/libstd/error.rs index 87e67931fe..454fa47cfb 100644 --- a/src/libstd/error.rs +++ b/src/libstd/error.rs @@ -13,9 +13,9 @@ //! # The `Error` trait //! //! `Error` is a trait representing the basic expectations for error values, -//! i.e. values of type `E` in `Result`. At a minimum, errors must provide +//! i.e. values of type `E` in [`Result`]. At a minimum, errors must provide //! a description, but they may optionally provide additional detail (via -//! `Display`) and cause chain information: +//! [`Display`]) and cause chain information: //! //! ``` //! use std::fmt::Display; @@ -27,12 +27,16 @@ //! } //! ``` //! -//! The `cause` method is generally used when errors cross "abstraction +//! The [`cause`] method is generally used when errors cross "abstraction //! boundaries", i.e. when a one module must report an error that is "caused" //! by an error from a lower-level module. This setup makes it possible for the //! high-level module to provide its own errors that do not commit to any //! particular implementation, but also reveal some of its implementation for -//! debugging via `cause` chains. +//! debugging via [`cause`] chains. +//! +//! [`Result`]: ../result/enum.Result.html +//! [`Display`]: ../fmt/trait.Display.html +//! [`cause`]: trait.Error.html#method.cause #![stable(feature = "rust1", since = "1.0.0")] @@ -61,9 +65,13 @@ use string; pub trait Error: Debug + Display { /// A short description of the error. /// - /// The description should not contain newlines or sentence-ending - /// punctuation, to facilitate embedding in larger user-facing - /// strings. + /// The description should only be used for a simple message. + /// It should not contain newlines or sentence-ending punctuation, + /// to facilitate embedding in larger user-facing strings. + /// For showing formatted error messages with more information see + /// [`Display`]. + /// + /// [`Display`]: ../fmt/trait.Display.html /// /// # Examples /// diff --git a/src/libstd/num/f32.rs b/src/libstd/f32.rs similarity index 100% rename from src/libstd/num/f32.rs rename to src/libstd/f32.rs diff --git a/src/libstd/num/f64.rs b/src/libstd/f64.rs similarity index 100% rename from src/libstd/num/f64.rs rename to src/libstd/f64.rs diff --git a/src/libstd/ffi/c_str.rs b/src/libstd/ffi/c_str.rs index 4d7b0434fd..3ad5b5627d 100644 --- a/src/libstd/ffi/c_str.rs +++ b/src/libstd/ffi/c_str.rs @@ -314,9 +314,11 @@ impl CString { } // Turns this `CString` into an empty string to prevent -// memory unsafe code from working by accident. +// memory unsafe code from working by accident. Inline +// to prevent LLVM from optimizing it away in debug builds. #[stable(feature = "cstring_drop", since = "1.13.0")] impl Drop for CString { + #[inline] fn drop(&mut self) { unsafe { *self.inner.get_unchecked_mut(0) = 0; } } diff --git a/src/libstd/ffi/os_str.rs b/src/libstd/ffi/os_str.rs index d93d3c7362..84b50f0446 100644 --- a/src/libstd/ffi/os_str.rs +++ b/src/libstd/ffi/os_str.rs @@ -53,17 +53,6 @@ impl OsString { OsString { inner: Buf::from_string(String::new()) } } - #[cfg(unix)] - fn _from_bytes(vec: Vec) -> Option { - use os::unix::ffi::OsStringExt; - Some(OsString::from_vec(vec)) - } - - #[cfg(windows)] - fn _from_bytes(vec: Vec) -> Option { - String::from_utf8(vec).ok().map(OsString::from) - } - /// Converts to an `OsStr` slice. #[stable(feature = "rust1", since = "1.0.0")] pub fn as_os_str(&self) -> &OsStr { diff --git a/src/libstd/fs.rs b/src/libstd/fs.rs index 576198564d..df5741d00a 100644 --- a/src/libstd/fs.rs +++ b/src/libstd/fs.rs @@ -83,6 +83,7 @@ pub struct Metadata(fs_imp::FileAttr); /// /// [`io::Result`]: ../io/type.Result.html #[stable(feature = "rust1", since = "1.0.0")] +#[derive(Debug)] pub struct ReadDir(fs_imp::ReadDir); /// Entries returned by the [`ReadDir`] iterator. @@ -1686,7 +1687,7 @@ impl AsInnerMut for DirBuilder { } } -#[cfg(test)] +#[cfg(all(test, not(target_os = "emscripten")))] mod tests { use io::prelude::*; @@ -1903,6 +1904,130 @@ mod tests { check!(fs::remove_file(filename)); } + #[test] + fn file_test_io_eof() { + let tmpdir = tmpdir(); + let filename = tmpdir.join("file_rt_io_file_test_eof.txt"); + let mut buf = [0; 256]; + { + let oo = OpenOptions::new().create_new(true).write(true).read(true).clone(); + let mut rw = check!(oo.open(&filename)); + assert_eq!(check!(rw.read(&mut buf)), 0); + assert_eq!(check!(rw.read(&mut buf)), 0); + } + check!(fs::remove_file(&filename)); + } + + #[test] + #[cfg(unix)] + fn file_test_io_read_write_at() { + use os::unix::fs::FileExt; + + let tmpdir = tmpdir(); + let filename = tmpdir.join("file_rt_io_file_test_read_write_at.txt"); + let mut buf = [0; 256]; + let write1 = "asdf"; + let write2 = "qwer-"; + let write3 = "-zxcv"; + let content = "qwer-asdf-zxcv"; + { + let oo = OpenOptions::new().create_new(true).write(true).read(true).clone(); + let mut rw = check!(oo.open(&filename)); + assert_eq!(check!(rw.write_at(write1.as_bytes(), 5)), write1.len()); + assert_eq!(check!(rw.seek(SeekFrom::Current(0))), 0); + assert_eq!(check!(rw.read_at(&mut buf, 5)), write1.len()); + assert_eq!(str::from_utf8(&buf[..write1.len()]), Ok(write1)); + assert_eq!(check!(rw.seek(SeekFrom::Current(0))), 0); + assert_eq!(check!(rw.read_at(&mut buf[..write2.len()], 0)), write2.len()); + assert_eq!(str::from_utf8(&buf[..write2.len()]), Ok("\0\0\0\0\0")); + assert_eq!(check!(rw.seek(SeekFrom::Current(0))), 0); + assert_eq!(check!(rw.write(write2.as_bytes())), write2.len()); + assert_eq!(check!(rw.seek(SeekFrom::Current(0))), 5); + assert_eq!(check!(rw.read(&mut buf)), write1.len()); + assert_eq!(str::from_utf8(&buf[..write1.len()]), Ok(write1)); + assert_eq!(check!(rw.seek(SeekFrom::Current(0))), 9); + assert_eq!(check!(rw.read_at(&mut buf[..write2.len()], 0)), write2.len()); + assert_eq!(str::from_utf8(&buf[..write2.len()]), Ok(write2)); + assert_eq!(check!(rw.seek(SeekFrom::Current(0))), 9); + assert_eq!(check!(rw.write_at(write3.as_bytes(), 9)), write3.len()); + assert_eq!(check!(rw.seek(SeekFrom::Current(0))), 9); + } + { + let mut read = check!(File::open(&filename)); + assert_eq!(check!(read.read_at(&mut buf, 0)), content.len()); + assert_eq!(str::from_utf8(&buf[..content.len()]), Ok(content)); + assert_eq!(check!(read.seek(SeekFrom::Current(0))), 0); + assert_eq!(check!(read.seek(SeekFrom::End(-5))), 9); + assert_eq!(check!(read.read_at(&mut buf, 0)), content.len()); + assert_eq!(str::from_utf8(&buf[..content.len()]), Ok(content)); + assert_eq!(check!(read.seek(SeekFrom::Current(0))), 9); + assert_eq!(check!(read.read(&mut buf)), write3.len()); + assert_eq!(str::from_utf8(&buf[..write3.len()]), Ok(write3)); + assert_eq!(check!(read.seek(SeekFrom::Current(0))), 14); + assert_eq!(check!(read.read_at(&mut buf, 0)), content.len()); + assert_eq!(str::from_utf8(&buf[..content.len()]), Ok(content)); + assert_eq!(check!(read.seek(SeekFrom::Current(0))), 14); + assert_eq!(check!(read.read_at(&mut buf, 14)), 0); + assert_eq!(check!(read.read_at(&mut buf, 15)), 0); + assert_eq!(check!(read.seek(SeekFrom::Current(0))), 14); + } + check!(fs::remove_file(&filename)); + } + + #[test] + #[cfg(windows)] + fn file_test_io_seek_read_write() { + use os::windows::fs::FileExt; + + let tmpdir = tmpdir(); + let filename = tmpdir.join("file_rt_io_file_test_seek_read_write.txt"); + let mut buf = [0; 256]; + let write1 = "asdf"; + let write2 = "qwer-"; + let write3 = "-zxcv"; + let content = "qwer-asdf-zxcv"; + { + let oo = OpenOptions::new().create_new(true).write(true).read(true).clone(); + let mut rw = check!(oo.open(&filename)); + assert_eq!(check!(rw.seek_write(write1.as_bytes(), 5)), write1.len()); + assert_eq!(check!(rw.seek(SeekFrom::Current(0))), 9); + assert_eq!(check!(rw.seek_read(&mut buf, 5)), write1.len()); + assert_eq!(str::from_utf8(&buf[..write1.len()]), Ok(write1)); + assert_eq!(check!(rw.seek(SeekFrom::Current(0))), 9); + assert_eq!(check!(rw.seek(SeekFrom::Start(0))), 0); + assert_eq!(check!(rw.write(write2.as_bytes())), write2.len()); + assert_eq!(check!(rw.seek(SeekFrom::Current(0))), 5); + assert_eq!(check!(rw.read(&mut buf)), write1.len()); + assert_eq!(str::from_utf8(&buf[..write1.len()]), Ok(write1)); + assert_eq!(check!(rw.seek(SeekFrom::Current(0))), 9); + assert_eq!(check!(rw.seek_read(&mut buf[..write2.len()], 0)), write2.len()); + assert_eq!(str::from_utf8(&buf[..write2.len()]), Ok(write2)); + assert_eq!(check!(rw.seek(SeekFrom::Current(0))), 5); + assert_eq!(check!(rw.seek_write(write3.as_bytes(), 9)), write3.len()); + assert_eq!(check!(rw.seek(SeekFrom::Current(0))), 14); + } + { + let mut read = check!(File::open(&filename)); + assert_eq!(check!(read.seek_read(&mut buf, 0)), content.len()); + assert_eq!(str::from_utf8(&buf[..content.len()]), Ok(content)); + assert_eq!(check!(read.seek(SeekFrom::Current(0))), 14); + assert_eq!(check!(read.seek(SeekFrom::End(-5))), 9); + assert_eq!(check!(read.seek_read(&mut buf, 0)), content.len()); + assert_eq!(str::from_utf8(&buf[..content.len()]), Ok(content)); + assert_eq!(check!(read.seek(SeekFrom::Current(0))), 14); + assert_eq!(check!(read.seek(SeekFrom::End(-5))), 9); + assert_eq!(check!(read.read(&mut buf)), write3.len()); + assert_eq!(str::from_utf8(&buf[..write3.len()]), Ok(write3)); + assert_eq!(check!(read.seek(SeekFrom::Current(0))), 14); + assert_eq!(check!(read.seek_read(&mut buf, 0)), content.len()); + assert_eq!(str::from_utf8(&buf[..content.len()]), Ok(content)); + assert_eq!(check!(read.seek(SeekFrom::Current(0))), 14); + assert_eq!(check!(read.seek_read(&mut buf, 14)), 0); + assert_eq!(check!(read.seek_read(&mut buf, 15)), 0); + } + check!(fs::remove_file(&filename)); + } + #[test] fn file_test_stat_is_correct_on_is_file() { let tmpdir = tmpdir(); @@ -2221,8 +2346,8 @@ mod tests { check!(fs::set_permissions(&out, attr.permissions())); } - #[cfg(windows)] #[test] + #[cfg(windows)] fn copy_file_preserves_streams() { let tmp = tmpdir(); check!(check!(File::create(tmp.join("in.txt:bunny"))).write("carrot".as_bytes())); diff --git a/src/libstd/io/buffered.rs b/src/libstd/io/buffered.rs index 53ddb55751..44dd4e9874 100644 --- a/src/libstd/io/buffered.rs +++ b/src/libstd/io/buffered.rs @@ -20,11 +20,15 @@ use memchr; /// The `BufReader` struct adds buffering to any reader. /// -/// It can be excessively inefficient to work directly with a `Read` instance. -/// For example, every call to `read` on `TcpStream` results in a system call. -/// A `BufReader` performs large, infrequent reads on the underlying `Read` +/// It can be excessively inefficient to work directly with a [`Read`] instance. +/// For example, every call to [`read`] on [`TcpStream`] results in a system call. +/// A `BufReader` performs large, infrequent reads on the underlying [`Read`] /// and maintains an in-memory buffer of the results. /// +/// [`Read`]: ../../std/io/trait.Read.html +/// [`read`]: ../../std/net/struct.TcpStream.html#method.read +/// [`TcpStream`]: ../../std/net/struct.TcpStream.html +/// /// # Examples /// /// ``` @@ -230,7 +234,7 @@ impl Seek for BufReader { 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. + // means we managed to allocate 8 exbibytes 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. @@ -254,7 +258,7 @@ impl Seek for BufReader { /// Wraps a writer and buffers its output. /// /// It can be excessively inefficient to work directly with something that -/// implements `Write`. For example, every call to `write` on `TcpStream` +/// implements [`Write`]. For example, every call to [`write`] on [`TcpStream`] /// results in a system call. A `BufWriter` keeps an in-memory buffer of data /// and writes it to an underlying writer in large, infrequent batches. /// @@ -262,7 +266,7 @@ impl Seek for BufReader { /// /// # Examples /// -/// Let's write the numbers one through ten to a `TcpStream`: +/// Let's write the numbers one through ten to a [`TcpStream`]: /// /// ```no_run /// use std::io::prelude::*; @@ -294,6 +298,10 @@ impl Seek for BufReader { /// By wrapping the stream with a `BufWriter`, these ten writes are all grouped /// together by the buffer, and will all be written out in one system call when /// the `stream` is dropped. +/// +/// [`Write`]: ../../std/io/trait.Write.html +/// [`write`]: ../../std/net/struct.TcpStream.html#method.write +/// [`TcpStream`]: ../../std/net/struct.TcpStream.html #[stable(feature = "rust1", since = "1.0.0")] pub struct BufWriter { inner: Option, @@ -1106,6 +1114,7 @@ mod tests { } #[test] + #[cfg_attr(target_os = "emscripten", ignore)] fn panic_in_write_doesnt_flush_in_drop() { static WRITES: AtomicUsize = AtomicUsize::new(0); diff --git a/src/libstd/io/cursor.rs b/src/libstd/io/cursor.rs index 1b836b7453..1b5023380a 100644 --- a/src/libstd/io/cursor.rs +++ b/src/libstd/io/cursor.rs @@ -10,26 +10,33 @@ use io::prelude::*; +use core::convert::TryInto; use cmp; use io::{self, SeekFrom, Error, ErrorKind}; /// A `Cursor` wraps another type and provides it with a -/// [`Seek`](trait.Seek.html) implementation. +/// [`Seek`] implementation. /// -/// Cursors are typically used with in-memory buffers to allow them to -/// implement `Read` and/or `Write`, allowing these buffers to be used +/// `Cursor`s are typically used with in-memory buffers to allow them to +/// implement [`Read`] and/or [`Write`], allowing these buffers to be used /// anywhere you might use a reader or writer that does actual I/O. /// /// The standard library implements some I/O traits on various types which -/// are commonly used as a buffer, like `Cursor>` and `Cursor<&[u8]>`. +/// are commonly used as a buffer, like `Cursor<`[`Vec`]`>` and +/// `Cursor<`[`&[u8]`][bytes]`>`. /// /// # Examples /// -/// We may want to write bytes to a [`File`][file] in our production +/// We may want to write bytes to a [`File`] in our production /// code, but use an in-memory buffer in our tests. We can do this with /// `Cursor`: /// -/// [file]: ../fs/struct.File.html +/// [`Seek`]: trait.Seek.html +/// [`Read`]: ../../std/io/trait.Read.html +/// [`Write`]: ../../std/io/trait.Write.html +/// [`Vec`]: ../../std/vec/struct.Vec.html +/// [bytes]: ../../std/primitive.slice.html +/// [`File`]: ../fs/struct.File.html /// /// ```no_run /// use std::io::prelude::*; @@ -242,18 +249,20 @@ impl<'a> Write for Cursor<&'a mut [u8]> { #[stable(feature = "rust1", since = "1.0.0")] impl Write for Cursor> { fn write(&mut self, buf: &[u8]) -> io::Result { + let pos: usize = self.position().try_into().map_err(|_| { + Error::new(ErrorKind::InvalidInput, + "cursor position exceeds maximum possible vector length") + })?; // Make sure the internal buffer is as least as big as where we // currently are - let pos = self.position(); - let amt = pos.saturating_sub(self.inner.len() as u64); - // use `resize` so that the zero filling is as efficient as possible let len = self.inner.len(); - self.inner.resize(len + amt as usize, 0); - + if len < pos { + // use `resize` so that the zero filling is as efficient as possible + self.inner.resize(pos, 0); + } // Figure out what bytes will be used to overwrite what's currently // there (left), and what will be appended on the end (right) { - let pos = pos as usize; let space = self.inner.len() - pos; let (left, right) = buf.split_at(cmp::min(space, buf.len())); self.inner[pos..pos + left.len()].copy_from_slice(left); @@ -261,7 +270,7 @@ impl Write for Cursor> { } // Bump us forward - self.set_position(pos + buf.len() as u64); + self.set_position((pos + buf.len()) as u64); Ok(buf.len()) } fn flush(&mut self) -> io::Result<()> { Ok(()) } @@ -383,7 +392,7 @@ mod tests { #[test] fn test_mem_reader() { - let mut reader = Cursor::new(vec!(0, 1, 2, 3, 4, 5, 6, 7)); + let mut reader = Cursor::new(vec![0, 1, 2, 3, 4, 5, 6, 7]); let mut buf = []; assert_eq!(reader.read(&mut buf).unwrap(), 0); assert_eq!(reader.position(), 0); @@ -405,7 +414,7 @@ mod tests { #[test] fn test_boxed_slice_reader() { - let mut reader = Cursor::new(vec!(0, 1, 2, 3, 4, 5, 6, 7).into_boxed_slice()); + let mut reader = Cursor::new(vec![0, 1, 2, 3, 4, 5, 6, 7].into_boxed_slice()); let mut buf = []; assert_eq!(reader.read(&mut buf).unwrap(), 0); assert_eq!(reader.position(), 0); @@ -427,7 +436,7 @@ mod tests { #[test] fn read_to_end() { - let mut reader = Cursor::new(vec!(0, 1, 2, 3, 4, 5, 6, 7)); + let mut reader = Cursor::new(vec![0, 1, 2, 3, 4, 5, 6, 7]); let mut v = Vec::new(); reader.read_to_end(&mut v).unwrap(); assert_eq!(v, [0, 1, 2, 3, 4, 5, 6, 7]); @@ -503,7 +512,7 @@ mod tests { assert_eq!(r.seek(SeekFrom::Start(10)).unwrap(), 10); assert_eq!(r.read(&mut [0]).unwrap(), 0); - let mut r = Cursor::new(vec!(10)); + let mut r = Cursor::new(vec![10]); assert_eq!(r.seek(SeekFrom::Start(10)).unwrap(), 10); assert_eq!(r.read(&mut [0]).unwrap(), 0); @@ -523,14 +532,14 @@ mod tests { let mut r = Cursor::new(&buf[..]); assert!(r.seek(SeekFrom::End(-2)).is_err()); - let mut r = Cursor::new(vec!(10)); + let mut r = Cursor::new(vec![10]); assert!(r.seek(SeekFrom::End(-2)).is_err()); let mut buf = [0]; let mut r = Cursor::new(&mut buf[..]); assert!(r.seek(SeekFrom::End(-2)).is_err()); - let mut r = Cursor::new(vec!(10).into_boxed_slice()); + let mut r = Cursor::new(vec![10].into_boxed_slice()); assert!(r.seek(SeekFrom::End(-2)).is_err()); } @@ -580,4 +589,12 @@ mod tests { let mut r = Cursor::new(Vec::new()); assert!(r.seek(SeekFrom::End(-2)).is_err()); } + + #[test] + #[cfg(target_pointer_width = "32")] + fn vec_seek_and_write_past_usize_max() { + let mut c = Cursor::new(Vec::new()); + c.set_position(::max_value() as u64 + 1); + assert!(c.write_all(&[1, 2, 3]).is_err()); + } } diff --git a/src/libstd/io/error.rs b/src/libstd/io/error.rs index ddf0030858..795c89c000 100644 --- a/src/libstd/io/error.rs +++ b/src/libstd/io/error.rs @@ -12,6 +12,7 @@ use error; use fmt; use result; use sys; +use convert::From; /// A specialized [`Result`](../result/enum.Result.html) type for I/O /// operations. @@ -62,6 +63,7 @@ pub struct Error { enum Repr { Os(i32), + Simple(ErrorKind), Custom(Box), } @@ -124,23 +126,28 @@ pub enum ErrorKind { InvalidInput, /// Data not valid for the operation were encountered. /// - /// Unlike `InvalidInput`, this typically means that the operation + /// Unlike [`InvalidInput`], this typically means that the operation /// parameters were valid, however the error was caused by malformed /// input data. /// /// For example, a function that reads a file into a string will error with /// `InvalidData` if the file's contents are not valid UTF-8. + /// + /// [`InvalidInput`]: #variant.InvalidInput #[stable(feature = "io_invalid_data", since = "1.2.0")] InvalidData, /// The I/O operation's timeout expired, causing it to be canceled. #[stable(feature = "rust1", since = "1.0.0")] TimedOut, /// An error returned when an operation could not be completed because a - /// call to `write` returned `Ok(0)`. + /// call to [`write()`] returned [`Ok(0)`]. /// /// This typically means that an operation could only succeed if it wrote a /// particular number of bytes but only a smaller number of bytes could be /// written. + /// + /// [`write()`]: ../../std/io/trait.Write.html#tymethod.write + /// [`Ok(0)`]: ../../std/io/type.Result.html #[stable(feature = "rust1", since = "1.0.0")] WriteZero, /// This operation was interrupted. @@ -171,6 +178,43 @@ pub enum ErrorKind { __Nonexhaustive, } +impl ErrorKind { + fn as_str(&self) -> &'static str { + match *self { + ErrorKind::NotFound => "entity not found", + ErrorKind::PermissionDenied => "permission denied", + ErrorKind::ConnectionRefused => "connection refused", + ErrorKind::ConnectionReset => "connection reset", + ErrorKind::ConnectionAborted => "connection aborted", + ErrorKind::NotConnected => "not connected", + ErrorKind::AddrInUse => "address in use", + ErrorKind::AddrNotAvailable => "address not available", + ErrorKind::BrokenPipe => "broken pipe", + ErrorKind::AlreadyExists => "entity already exists", + ErrorKind::WouldBlock => "operation would block", + ErrorKind::InvalidInput => "invalid input parameter", + ErrorKind::InvalidData => "invalid data", + ErrorKind::TimedOut => "timed out", + ErrorKind::WriteZero => "write zero", + ErrorKind::Interrupted => "operation interrupted", + ErrorKind::Other => "other os error", + ErrorKind::UnexpectedEof => "unexpected end of file", + ErrorKind::__Nonexhaustive => unreachable!() + } + } +} + +/// Intended for use for errors not exposed to the user, where allocating onto +/// the heap (for normal construction via Error::new) is too costly. +#[stable(feature = "io_error_from_errorkind", since = "1.14.0")] +impl From for Error { + fn from(kind: ErrorKind) -> Error { + Error { + repr: Repr::Simple(kind) + } + } +} + impl Error { /// Creates a new I/O error from a known kind of error as well as an /// arbitrary error payload. @@ -285,6 +329,7 @@ impl Error { match self.repr { Repr::Os(i) => Some(i), Repr::Custom(..) => None, + Repr::Simple(..) => None, } } @@ -317,6 +362,7 @@ impl Error { pub fn get_ref(&self) -> Option<&(error::Error+Send+Sync+'static)> { match self.repr { Repr::Os(..) => None, + Repr::Simple(..) => None, Repr::Custom(ref c) => Some(&*c.error), } } @@ -387,6 +433,7 @@ impl Error { pub fn get_mut(&mut self) -> Option<&mut (error::Error+Send+Sync+'static)> { match self.repr { Repr::Os(..) => None, + Repr::Simple(..) => None, Repr::Custom(ref mut c) => Some(&mut *c.error), } } @@ -420,6 +467,7 @@ impl Error { pub fn into_inner(self) -> Option> { match self.repr { Repr::Os(..) => None, + Repr::Simple(..) => None, Repr::Custom(c) => Some(c.error) } } @@ -447,6 +495,7 @@ impl Error { match self.repr { Repr::Os(code) => sys::decode_error_kind(code), Repr::Custom(ref c) => c.kind, + Repr::Simple(kind) => kind, } } } @@ -458,6 +507,7 @@ impl fmt::Debug for Repr { fmt.debug_struct("Os").field("code", code) .field("message", &sys::os::error_string(*code)).finish(), Repr::Custom(ref c) => fmt.debug_tuple("Custom").field(c).finish(), + Repr::Simple(kind) => fmt.debug_tuple("Kind").field(&kind).finish(), } } } @@ -471,6 +521,7 @@ impl fmt::Display for Error { write!(fmt, "{} (os error {})", detail, code) } Repr::Custom(ref c) => c.error.fmt(fmt), + Repr::Simple(kind) => write!(fmt, "{}", kind.as_str()), } } } @@ -479,27 +530,7 @@ impl fmt::Display for Error { impl error::Error for Error { fn description(&self) -> &str { match self.repr { - Repr::Os(..) => match self.kind() { - ErrorKind::NotFound => "entity not found", - ErrorKind::PermissionDenied => "permission denied", - ErrorKind::ConnectionRefused => "connection refused", - ErrorKind::ConnectionReset => "connection reset", - ErrorKind::ConnectionAborted => "connection aborted", - ErrorKind::NotConnected => "not connected", - ErrorKind::AddrInUse => "address in use", - ErrorKind::AddrNotAvailable => "address not available", - ErrorKind::BrokenPipe => "broken pipe", - ErrorKind::AlreadyExists => "entity already exists", - ErrorKind::WouldBlock => "operation would block", - ErrorKind::InvalidInput => "invalid input parameter", - ErrorKind::InvalidData => "invalid data", - ErrorKind::TimedOut => "timed out", - ErrorKind::WriteZero => "write zero", - ErrorKind::Interrupted => "operation interrupted", - ErrorKind::Other => "other os error", - ErrorKind::UnexpectedEof => "unexpected end of file", - ErrorKind::__Nonexhaustive => unreachable!() - }, + Repr::Os(..) | Repr::Simple(..) => self.kind().as_str(), Repr::Custom(ref c) => c.error.description(), } } @@ -507,6 +538,7 @@ impl error::Error for Error { fn cause(&self) -> Option<&error::Error> { match self.repr { Repr::Os(..) => None, + Repr::Simple(..) => None, Repr::Custom(ref c) => c.error.cause(), } } diff --git a/src/libstd/io/impls.rs b/src/libstd/io/impls.rs index cd05e6b5de..6b26c01663 100644 --- a/src/libstd/io/impls.rs +++ b/src/libstd/io/impls.rs @@ -147,6 +147,10 @@ impl BufRead for Box { // ============================================================================= // In-memory buffer implementations +/// Read is implemented for `&[u8]` by copying from the slice. +/// +/// Note that reading updates the slice to point to the yet unread part. +/// The slice will be empty when EOF is reached. #[stable(feature = "rust1", since = "1.0.0")] impl<'a> Read for &'a [u8] { #[inline] @@ -180,6 +184,11 @@ impl<'a> BufRead for &'a [u8] { fn consume(&mut self, amt: usize) { *self = &self[amt..]; } } +/// Write is implemented for `&mut [u8]` by copying into the slice, overwriting +/// its data. +/// +/// Note that writing updates the slice to point to the yet unwritten part. +/// The slice will be empty when it has been completely overwritten. #[stable(feature = "rust1", since = "1.0.0")] impl<'a> Write for &'a mut [u8] { #[inline] @@ -204,6 +213,8 @@ impl<'a> Write for &'a mut [u8] { fn flush(&mut self) -> io::Result<()> { Ok(()) } } +/// Write is implemented for `Vec` by appending to the vector. +/// The vector will grow as needed. #[stable(feature = "rust1", since = "1.0.0")] impl Write for Vec { #[inline] diff --git a/src/libstd/io/mod.rs b/src/libstd/io/mod.rs index 06609cfad1..193f396c0d 100644 --- a/src/libstd/io/mod.rs +++ b/src/libstd/io/mod.rs @@ -12,18 +12,15 @@ //! //! The `std::io` module contains a number of common things you'll need //! when doing input and output. The most core part of this module is -//! the [`Read`][read] and [`Write`][write] traits, which provide the +//! the [`Read`] and [`Write`] traits, which provide the //! most general interface for reading and writing input and output. //! -//! [read]: trait.Read.html -//! [write]: trait.Write.html -//! //! # Read and Write //! -//! Because they are traits, `Read` and `Write` are implemented by a number +//! Because they are traits, [`Read`] and [`Write`] are implemented by a number //! of other types, and you can implement them for your types too. As such, //! you'll see a few different types of I/O throughout the documentation in -//! this module: `File`s, `TcpStream`s, and sometimes even `Vec`s. For +//! this module: [`File`]s, [`TcpStream`]s, and sometimes even [`Vec`]s. For //! example, `Read` adds a `read()` method, which we can use on `File`s: //! //! ``` @@ -43,15 +40,15 @@ //! # } //! ``` //! -//! `Read` and `Write` are so important, implementors of the two traits have a +//! [`Read`] and [`Write`] are so important, implementors of the two traits have a //! nickname: readers and writers. So you'll sometimes see 'a reader' instead -//! of 'a type that implements the `Read` trait'. Much easier! +//! of 'a type that implements the [`Read`] trait'. Much easier! //! //! ## Seek and BufRead //! -//! Beyond that, there are two important traits that are provided: [`Seek`][seek] -//! and [`BufRead`][bufread]. Both of these build on top of a reader to control -//! how the reading happens. `Seek` lets you control where the next byte is +//! Beyond that, there are two important traits that are provided: [`Seek`] +//! and [`BufRead`]. Both of these build on top of a reader to control +//! how the reading happens. [`Seek`] lets you control where the next byte is //! coming from: //! //! ``` @@ -75,21 +72,18 @@ //! # } //! ``` //! -//! [seek]: trait.Seek.html -//! [bufread]: trait.BufRead.html -//! -//! `BufRead` uses an internal buffer to provide a number of other ways to read, but +//! [`BufRead`] uses an internal buffer to provide a number of other ways to read, but //! to show it off, we'll need to talk about buffers in general. Keep reading! //! //! ## BufReader and BufWriter //! //! Byte-based interfaces are unwieldy and can be inefficient, as we'd need to be //! making near-constant calls to the operating system. To help with this, -//! `std::io` comes with two structs, `BufReader` and `BufWriter`, which wrap +//! `std::io` comes with two structs, [`BufReader`] and [`BufWriter`], which wrap //! readers and writers. The wrapper uses a buffer, reducing the number of //! calls and providing nicer methods for accessing exactly what you want. //! -//! For example, `BufReader` works with the `BufRead` trait to add extra +//! For example, [`BufReader`] works with the [`BufRead`] trait to add extra //! methods to any reader: //! //! ``` @@ -111,8 +105,8 @@ //! # } //! ``` //! -//! `BufWriter` doesn't add any new ways of writing; it just buffers every call -//! to [`write()`][write()]: +//! [`BufWriter`] doesn't add any new ways of writing; it just buffers every call +//! to [`write()`]: //! //! ``` //! use std::io; @@ -134,8 +128,6 @@ //! # } //! ``` //! -//! [write()]: trait.Write.html#tymethod.write -//! //! ## Standard input and output //! //! A very common source of input is standard input: @@ -165,13 +157,13 @@ //! # } //! ``` //! -//! Of course, using `io::stdout()` directly is less common than something like -//! `println!`. +//! Of course, using [`io::stdout()`] directly is less common than something like +//! [`println!`]. //! //! ## Iterator types //! //! A large number of the structures provided by `std::io` are for various -//! ways of iterating over I/O. For example, `Lines` is used to split over +//! ways of iterating over I/O. For example, [`Lines`] is used to split over //! lines: //! //! ``` @@ -211,10 +203,10 @@ //! //! ## io::Result //! -//! Last, but certainly not least, is [`io::Result`][result]. This type is used +//! Last, but certainly not least, is [`io::Result`]. This type is used //! as the return type of many `std::io` functions that can cause an error, and //! can be returned from your own functions as well. Many of the examples in this -//! module use the [`try!`][try] macro: +//! module use the [`try!`] macro: //! //! ``` //! use std::io; @@ -230,14 +222,11 @@ //! } //! ``` //! -//! The return type of `read_input()`, `io::Result<()>`, is a very common type -//! for functions which don't have a 'real' return value, but do want to return -//! errors if they happen. In this case, the only purpose of this function is +//! The return type of `read_input()`, [`io::Result<()>`][`io::Result`], is a very +//! common type for functions which don't have a 'real' return value, but do want to +//! return errors if they happen. In this case, the only purpose of this function is //! to read the line and print it, so we use `()`. //! -//! [result]: type.Result.html -//! [try]: ../macro.try.html -//! //! ## Platform-specific behavior //! //! Many I/O functions throughout the standard library are documented to indicate @@ -246,6 +235,22 @@ //! any possibly unclear semantics. Note, however, that this is informative, not a binding //! contract. The implementation of many of these functions are subject to change over //! time and may call fewer or more syscalls/library functions. +//! +//! [`Read`]: trait.Read.html +//! [`Write`]: trait.Write.html +//! [`Seek`]: trait.Seek.html +//! [`BufRead`]: trait.BufRead.html +//! [`File`]: ../fs/struct.File.html +//! [`TcpStream`]: ../net/struct.TcpStream.html +//! [`Vec`]: ../vec/struct.Vec.html +//! [`BufReader`]: struct.BufReader.html +//! [`BufWriter`]: struct.BufWriter.html +//! [`write()`]: trait.Write.html#tymethod.write +//! [`io::stdout()`]: fn.stdout.html +//! [`println!`]: ../macro.println.html +//! [`Lines`]: struct.Lines.html +//! [`io::Result`]: type.Result.html +//! [`try!`]: ../macro.try.html #![stable(feature = "rust1", since = "1.0.0")] @@ -284,7 +289,7 @@ mod lazy; mod util; mod stdio; -const DEFAULT_BUF_SIZE: usize = 8 * 1024; +const DEFAULT_BUF_SIZE: usize = ::sys_common::io::DEFAULT_BUF_SIZE; // A few methods below (read_to_string, read_line) will append data into a // `String` buffer, but we need to be pretty careful when doing this. The @@ -1149,10 +1154,7 @@ fn read_until(r: &mut R, delim: u8, buf: &mut Vec) /// /// For example, reading line-by-line is inefficient without using a buffer, so /// if you want to read by line, you'll need `BufRead`, which includes a -/// [`read_line()`][readline] method as well as a [`lines()`][lines] iterator. -/// -/// [readline]: #method.read_line -/// [lines]: #method.lines +/// [`read_line()`] method as well as a [`lines()`] iterator. /// /// # Examples /// @@ -1168,14 +1170,17 @@ fn read_until(r: &mut R, delim: u8, buf: &mut Vec) /// } /// ``` /// -/// If you have something that implements `Read`, you can use the [`BufReader` -/// type][bufreader] to turn it into a `BufRead`. +/// If you have something that implements [`Read`], you can use the [`BufReader` +/// type][`BufReader`] to turn it into a `BufRead`. /// -/// For example, [`File`][file] implements `Read`, but not `BufRead`. -/// `BufReader` to the rescue! +/// For example, [`File`] implements [`Read`], but not `BufRead`. +/// [`BufReader`] to the rescue! /// -/// [bufreader]: struct.BufReader.html -/// [file]: ../fs/struct.File.html +/// [`BufReader`]: struct.BufReader.html +/// [`File`]: ../fs/struct.File.html +/// [`read_line()`]: #method.read_line +/// [`lines()`]: #method.lines +/// [`Read`]: trait.Read.html /// /// ``` /// use std::io::{self, BufReader}; @@ -1199,13 +1204,13 @@ pub trait BufRead: Read { /// Fills the internal buffer of this object, returning the buffer contents. /// /// This function is a lower-level call. It needs to be paired with the - /// [`consume`][consume] method to function properly. When calling this + /// [`consume()`] method to function properly. When calling this /// method, none of the contents will be "read" in the sense that later - /// calling `read` may return the same contents. As such, `consume` must be - /// called with the number of bytes that are consumed from this buffer to + /// calling `read` may return the same contents. As such, [`consume()`] must + /// be called with the number of bytes that are consumed from this buffer to /// ensure that the bytes are never returned twice. /// - /// [consume]: #tymethod.consume + /// [`consume()`]: #tymethod.consume /// /// An empty buffer returned indicates that the stream has reached EOF. /// @@ -1246,38 +1251,36 @@ pub trait BufRead: Read { /// so they should no longer be returned in calls to `read`. /// /// This function is a lower-level call. It needs to be paired with the - /// [`fill_buf`][fillbuf] method to function properly. This function does + /// [`fill_buf()`] method to function properly. This function does /// not perform any I/O, it simply informs this object that some amount of - /// its buffer, returned from `fill_buf`, has been consumed and should no - /// longer be returned. As such, this function may do odd things if - /// `fill_buf` isn't called before calling it. - /// - /// [fillbuf]: #tymethod.fill_buf + /// its buffer, returned from [`fill_buf()`], has been consumed and should + /// no longer be returned. As such, this function may do odd things if + /// [`fill_buf()`] isn't called before calling it. /// /// The `amt` must be `<=` the number of bytes in the buffer returned by - /// `fill_buf`. + /// [`fill_buf()`]. /// /// # Examples /// - /// Since `consume()` is meant to be used with [`fill_buf()`][fillbuf], + /// Since `consume()` is meant to be used with [`fill_buf()`], /// that method's example includes an example of `consume()`. + /// + /// [`fill_buf()`]: #tymethod.fill_buf #[stable(feature = "rust1", since = "1.0.0")] fn consume(&mut self, amt: usize); - /// Read all bytes into `buf` until the delimiter `byte` is reached. + /// Read all bytes into `buf` until the delimiter `byte` or EOF is reached. /// /// This function will read bytes from the underlying stream until the /// delimiter or EOF is found. Once found, all bytes up to, and including, /// the delimiter (if found) will be appended to `buf`. /// - /// If this reader is currently at EOF then this function will not modify - /// `buf` and will return `Ok(n)` where `n` is the number of bytes which - /// were read. + /// If successful, this function will return the total number of bytes read. /// /// # Errors /// - /// This function will ignore all instances of `ErrorKind::Interrupted` and - /// will otherwise return any errors returned by `fill_buf`. + /// This function will ignore all instances of [`ErrorKind::Interrupted`] and + /// will otherwise return any errors returned by [`fill_buf()`]. /// /// If an I/O error is encountered then all bytes read so far will be /// present in `buf` and its length will have been adjusted appropriately. @@ -1287,6 +1290,9 @@ pub trait BufRead: Read { /// A locked standard input implements `BufRead`. In this example, we'll /// read from standard input until we see an `a` byte. /// + /// [`fill_buf()`]: #tymethod.fill_buf + /// [`ErrorKind::Interrupted`]: enum.ErrorKind.html#variant.Interrupted + /// /// ``` /// use std::io; /// use std::io::prelude::*; @@ -1315,25 +1321,24 @@ pub trait BufRead: Read { /// up to, and including, the delimiter (if found) will be appended to /// `buf`. /// - /// If this reader is currently at EOF then this function will not modify - /// `buf` and will return `Ok(n)` where `n` is the number of bytes which - /// were read. + /// If successful, this function will return the total number of bytes read. /// /// # Errors /// - /// This function has the same error semantics as `read_until` and will also - /// return an error if the read bytes are not valid UTF-8. If an I/O error - /// is encountered then `buf` may contain some bytes already read in the - /// event that all data read so far was valid UTF-8. + /// This function has the same error semantics as [`read_until()`] and will + /// also return an error if the read bytes are not valid UTF-8. If an I/O + /// error is encountered then `buf` may contain some bytes already read in + /// the event that all data read so far was valid UTF-8. /// /// # Examples /// /// A locked standard input implements `BufRead`. In this example, we'll /// read all of the lines from standard input. If we were to do this in - /// an actual project, the [`lines()`][lines] method would be easier, of + /// an actual project, the [`lines()`] method would be easier, of /// course. /// - /// [lines]: #method.lines + /// [`lines()`]: #method.lines + /// [`read_until()`]: #method.read_until /// /// ``` /// use std::io; @@ -1362,17 +1367,21 @@ pub trait BufRead: Read { /// `byte`. /// /// The iterator returned from this function will return instances of - /// `io::Result>`. Each vector returned will *not* have the - /// delimiter byte at the end. + /// [`io::Result`]`<`[`Vec`]`>`. Each vector returned will *not* have + /// the delimiter byte at the end. /// - /// This function will yield errors whenever `read_until` would have also - /// yielded an error. + /// This function will yield errors whenever [`read_until()`] would have + /// also yielded an error. /// /// # Examples /// /// A locked standard input implements `BufRead`. In this example, we'll /// read some input from standard input, splitting on commas. /// + /// [`io::Result`]: type.Result.html + /// [`Vec`]: ../vec/struct.Vec.html + /// [`read_until()`]: #method.read_until + /// /// ``` /// use std::io; /// use std::io::prelude::*; @@ -1391,9 +1400,12 @@ pub trait BufRead: Read { /// Returns an iterator over the lines of this reader. /// /// The iterator returned from this function will yield instances of - /// `io::Result`. Each string returned will *not* have a newline + /// [`io::Result`]`<`[`String`]`>`. Each string returned will *not* have a newline /// byte (the 0xA byte) or CRLF (0xD, 0xA bytes) at the end. /// + /// [`io::Result`]: type.Result.html + /// [`String`]: ../string/struct.String.html + /// /// # Examples /// /// A locked standard input implements `BufRead`: @@ -1416,10 +1428,10 @@ pub trait BufRead: Read { /// Adaptor to chain together two readers. /// -/// This struct is generally created by calling [`chain()`][chain] on a reader. -/// Please see the documentation of `chain()` for more details. +/// This struct is generally created by calling [`chain()`] on a reader. +/// Please see the documentation of [`chain()`] for more details. /// -/// [chain]: trait.Read.html#method.chain +/// [`chain()`]: trait.Read.html#method.chain #[stable(feature = "rust1", since = "1.0.0")] pub struct Chain { first: T, @@ -1432,7 +1444,7 @@ impl Read for Chain { fn read(&mut self, buf: &mut [u8]) -> Result { if !self.done_first { match self.first.read(buf)? { - 0 => { self.done_first = true; } + 0 if buf.len() != 0 => { self.done_first = true; } n => return Ok(n), } } @@ -1524,7 +1536,7 @@ impl Take { /// # Ok(()) /// # } /// ``` - #[unstable(feature = "io_take_into_inner", issue = "0")] + #[unstable(feature = "io_take_into_inner", issue = "23755")] pub fn into_inner(self) -> T { self.inner } @@ -1580,10 +1592,10 @@ fn read_one_byte(reader: &mut Read) -> Option> { /// An iterator over `u8` values of a reader. /// -/// This struct is generally created by calling [`bytes()`][bytes] on a reader. -/// Please see the documentation of `bytes()` for more details. +/// This struct is generally created by calling [`bytes()`] on a reader. +/// Please see the documentation of [`bytes()`] for more details. /// -/// [bytes]: trait.Read.html#method.bytes +/// [`bytes()`]: trait.Read.html#method.bytes #[stable(feature = "rust1", since = "1.0.0")] pub struct Bytes { inner: R, @@ -1761,6 +1773,7 @@ mod tests { use super::repeat; #[test] + #[cfg_attr(target_os = "emscripten", ignore)] fn read_until() { let mut buf = Cursor::new(&b"12"[..]); let mut v = Vec::new(); @@ -1959,7 +1972,19 @@ mod tests { cmp_bufread(chain1, chain2, &testdata[..]); } + #[test] + fn chain_zero_length_read_is_not_eof() { + let a = b"A"; + let b = b"B"; + let mut s = String::new(); + let mut chain = (&a[..]).chain(&b[..]); + chain.read(&mut []).unwrap(); + chain.read_to_string(&mut s).unwrap(); + assert_eq!("AB", s); + } + #[bench] + #[cfg_attr(target_os = "emscripten", ignore)] fn bench_read_to_end(b: &mut test::Bencher) { b.iter(|| { let mut lr = repeat(1).take(10000000); diff --git a/src/libstd/io/stdio.rs b/src/libstd/io/stdio.rs index 9a782e95f6..1777b79ea1 100644 --- a/src/libstd/io/stdio.rs +++ b/src/libstd/io/stdio.rs @@ -125,13 +125,10 @@ impl io::Read for Maybe { } fn handle_ebadf(r: io::Result, default: T) -> io::Result { - #[cfg(windows)] - const ERR: i32 = ::sys::c::ERROR_INVALID_HANDLE as i32; - #[cfg(not(windows))] - const ERR: i32 = ::libc::EBADF as i32; + use sys::stdio::EBADF_ERR; match r { - Err(ref e) if e.raw_os_error() == Some(ERR) => Ok(default), + Err(ref e) if e.raw_os_error() == Some(EBADF_ERR) => Ok(default), r => r } } @@ -217,15 +214,7 @@ pub fn stdin() -> Stdin { _ => Maybe::Fake }; - // 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. - Arc::new(Mutex::new(if cfg!(windows) { - BufReader::with_capacity(8 * 1024, stdin) - } else { - BufReader::new(stdin) - })) + Arc::new(Mutex::new(BufReader::with_capacity(stdio::STDIN_BUF_SIZE, stdin))) } } @@ -593,11 +582,11 @@ impl<'a> Write for StderrLock<'a> { with a more general mechanism", issue = "0")] #[doc(hidden)] -pub fn set_panic(sink: Box) -> Option> { +pub fn set_panic(sink: Option>) -> Option> { use panicking::LOCAL_STDERR; use mem; LOCAL_STDERR.with(move |slot| { - mem::replace(&mut *slot.borrow_mut(), Some(sink)) + mem::replace(&mut *slot.borrow_mut(), sink) }).and_then(|mut s| { let _ = s.flush(); Some(s) @@ -617,10 +606,10 @@ pub fn set_panic(sink: Box) -> Option> { with a more general mechanism", issue = "0")] #[doc(hidden)] -pub fn set_print(sink: Box) -> Option> { +pub fn set_print(sink: Option>) -> Option> { use mem; LOCAL_STDOUT.with(move |slot| { - mem::replace(&mut *slot.borrow_mut(), Some(sink)) + mem::replace(&mut *slot.borrow_mut(), sink) }).and_then(|mut s| { let _ = s.flush(); Some(s) @@ -668,6 +657,7 @@ mod tests { use super::*; #[test] + #[cfg_attr(target_os = "emscripten", ignore)] fn panic_doesnt_poison() { thread::spawn(|| { let _a = stdin(); diff --git a/src/libstd/lib.rs b/src/libstd/lib.rs index 952d584763..12dbbe3c46 100644 --- a/src/libstd/lib.rs +++ b/src/libstd/lib.rs @@ -210,25 +210,46 @@ test(no_crate_inject, attr(deny(warnings))), test(attr(allow(dead_code, deprecated, unused_variables, unused_mut))))] +// Don't link to std. We are std. +#![no_std] + +#![deny(missing_docs)] + +// Tell the compiler to link to either panic_abort or panic_unwind #![needs_panic_runtime] +// Always use alloc_system during stage0 since jemalloc might be unavailable or +// disabled (Issue #30592) +#![cfg_attr(stage0, feature(alloc_system))] + +// Turn warnings into errors, but only after stage0, where it can be useful for +// code to emit warnings during language transitions +#![cfg_attr(not(stage0), deny(warnings))] + +// std may use features in a platform-specific way +#![allow(unused_features)] + +// std is implemented with unstable features, many of which are internal +// compiler details that will never be stable #![feature(alloc)] #![feature(allow_internal_unstable)] #![feature(asm)] #![feature(associated_consts)] #![feature(borrow_state)] #![feature(box_syntax)] +#![feature(cfg_target_has_atomic)] #![feature(cfg_target_thread_local)] #![feature(cfg_target_vendor)] #![feature(char_escape_debug)] #![feature(char_internals)] #![feature(collections)] #![feature(collections_bound)] +#![feature(collections_range)] #![feature(compiler_builtins_lib)] #![feature(const_fn)] #![feature(core_float)] #![feature(core_intrinsics)] -#![feature(dotdot_in_tuple_patterns)] +#![cfg_attr(stage0, feature(dotdot_in_tuple_patterns))] #![feature(dropck_parametricity)] #![feature(float_extras)] #![feature(float_from_str_radix)] @@ -239,13 +260,13 @@ #![feature(heap_api)] #![feature(inclusive_range)] #![feature(int_error_internals)] +#![feature(integer_atomics)] #![feature(into_cow)] #![feature(lang_items)] #![feature(libc)] #![feature(link_args)] #![feature(linkage)] #![feature(macro_reexport)] -#![cfg_attr(test, feature(map_values_mut))] #![feature(needs_panic_runtime)] #![feature(num_bits_bytes)] #![feature(old_wrapping)] @@ -276,27 +297,18 @@ #![feature(unboxed_closures)] #![feature(unicode)] #![feature(unique)] -#![cfg_attr(stage0, feature(unsafe_no_drop_flag))] #![feature(unwind_attributes)] #![feature(vec_push_all)] #![feature(zero_one)] #![cfg_attr(test, feature(update_panic_count))] -// Issue# 30592: Systematically use alloc_system during stage0 since jemalloc -// might be unavailable or disabled -#![cfg_attr(stage0, feature(alloc_system))] - -// Don't link to std. We are std. -#![no_std] - -#![deny(missing_docs)] -#![allow(unused_features)] // std may use features in a platform-specific way -#![cfg_attr(not(stage0), deny(warnings))] - +// Explicitly import the prelude. The compiler uses this same unstable attribute +// to import the prelude implicitly when building crates that depend on std. #[prelude_import] #[allow(unused)] use prelude::v1::*; +// Access to Bencher, etc. #[cfg(test)] extern crate test; // We want to reexport a few macros from core but libcore has already been @@ -324,11 +336,22 @@ extern crate alloc_system; // compiler-rt intrinsics extern crate compiler_builtins; -// Make std testable by not duplicating lang items and other globals. See #2912 +// During testing, this crate is not actually the "real" std library, but rather +// it links to the real std library, which was compiled from this same source +// code. So any lang items std defines are conditionally excluded (or else they +// wolud generate duplicate lang item errors), and any globals it defines are +// _not_ the globals used by "real" std. So this import, defined only during +// testing gives test-std access to real-std lang items and globals. See #2912 #[cfg(test)] extern crate std as realstd; -// NB: These reexports are in the order they should be listed in rustdoc +// The standard macros that are not built-in to the compiler. +#[macro_use] +mod macros; + +// The Rust prelude +pub mod prelude; +// Public module declarations and reexports #[stable(feature = "rust1", since = "1.0.0")] pub use core::any; #[stable(feature = "rust1", since = "1.0.0")] @@ -361,48 +384,6 @@ pub use core::raw; pub use core::result; #[stable(feature = "rust1", since = "1.0.0")] pub use core::option; - -pub mod error; - -#[stable(feature = "rust1", since = "1.0.0")] -pub use alloc::boxed; -#[stable(feature = "rust1", since = "1.0.0")] -pub use alloc::rc; - -#[stable(feature = "rust1", since = "1.0.0")] -pub use core_collections::borrow; -#[stable(feature = "rust1", since = "1.0.0")] -pub use core_collections::fmt; -#[stable(feature = "rust1", since = "1.0.0")] -pub use core_collections::slice; -#[stable(feature = "rust1", since = "1.0.0")] -pub use core_collections::str; -#[stable(feature = "rust1", since = "1.0.0")] -pub use core_collections::string; -#[stable(feature = "rust1", since = "1.0.0")] -pub use core_collections::vec; - -#[stable(feature = "rust1", since = "1.0.0")] -pub use rustc_unicode::char; - -/* Exported macros */ - -#[macro_use] -mod macros; - -mod rtdeps; - -/* The Prelude. */ - -pub mod prelude; - - -/* Primitive types */ - -// NB: slice and str are primitive types too, but their module docs + primitive -// doc pages are inlined from the public re-exports of core_collections::{slice, -// str} above. - #[stable(feature = "rust1", since = "1.0.0")] pub use core::isize; #[stable(feature = "rust1", since = "1.0.0")] @@ -413,7 +394,6 @@ pub use core::i16; pub use core::i32; #[stable(feature = "rust1", since = "1.0.0")] pub use core::i64; - #[stable(feature = "rust1", since = "1.0.0")] pub use core::usize; #[stable(feature = "rust1", since = "1.0.0")] @@ -424,46 +404,62 @@ pub use core::u16; pub use core::u32; #[stable(feature = "rust1", since = "1.0.0")] pub use core::u64; +#[stable(feature = "rust1", since = "1.0.0")] +pub use alloc::boxed; +#[stable(feature = "rust1", since = "1.0.0")] +pub use alloc::rc; +#[stable(feature = "rust1", since = "1.0.0")] +pub use core_collections::borrow; +#[stable(feature = "rust1", since = "1.0.0")] +pub use core_collections::fmt; +#[stable(feature = "rust1", since = "1.0.0")] +pub use core_collections::slice; +#[stable(feature = "rust1", since = "1.0.0")] +pub use core_collections::str; +#[stable(feature = "rust1", since = "1.0.0")] +pub use core_collections::string; +#[stable(feature = "rust1", since = "1.0.0")] +pub use core_collections::vec; +#[stable(feature = "rust1", since = "1.0.0")] +pub use rustc_unicode::char; -#[path = "num/f32.rs"] pub mod f32; -#[path = "num/f64.rs"] pub mod f64; - -pub mod ascii; - -/* Common traits */ - -pub mod num; - -/* Runtime and platform support */ +pub mod f32; +pub mod f64; #[macro_use] pub mod thread; - +pub mod ascii; pub mod collections; pub mod env; +pub mod error; pub mod ffi; pub mod fs; pub mod io; pub mod net; +pub mod num; pub mod os; pub mod panic; pub mod path; pub mod process; pub mod sync; pub mod time; -mod memchr; +// Platform-abstraction modules #[macro_use] -#[path = "sys/common/mod.rs"] mod sys_common; - -#[cfg(unix)] -#[path = "sys/unix/mod.rs"] mod sys; -#[cfg(windows)] -#[path = "sys/windows/mod.rs"] mod sys; +mod sys_common; +mod sys; -pub mod rt; +// Private support modules mod panicking; mod rand; +mod memchr; + +// This module just defines per-platform native library dependencies +mod rtdeps; + +// The runtime entry point and a few unstable public functions used by the +// compiler +pub mod rt; // 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 diff --git a/src/libstd/macros.rs b/src/libstd/macros.rs index c78840bd42..0ce6b0a943 100644 --- a/src/libstd/macros.rs +++ b/src/libstd/macros.rs @@ -112,12 +112,14 @@ macro_rules! print { /// # Examples /// /// ``` +/// println!(); /// println!("hello there!"); /// println!("format {} arguments", "some"); /// ``` #[macro_export] #[stable(feature = "rust1", since = "1.0.0")] macro_rules! println { + () => (print!("\n")); ($fmt:expr) => (print!(concat!($fmt, "\n"))); ($fmt:expr, $($arg:tt)*) => (print!(concat!($fmt, "\n"), $($arg)*)); } @@ -284,7 +286,7 @@ pub mod builtin { /// // fn concat_idents!(new, fun, name) { } // not usable in this way! /// # } /// ``` - #[unstable(feature = "concat_idents", issue = "29599")] + #[unstable(feature = "concat_idents_macro", issue = "29599")] #[macro_export] macro_rules! concat_idents { ($($e:ident),*) => ({ /* compiler built-in */ }) @@ -379,9 +381,11 @@ pub mod builtin { /// Includes a utf8-encoded file as a string. /// + /// The file is located relative to the current file. (similarly to how + /// modules are found) + /// /// This macro will yield an expression of type `&'static str` which is the - /// contents of the filename specified. The file is located relative to the - /// current file (similarly to how modules are found), + /// contents of the file. /// /// # Examples /// @@ -394,9 +398,11 @@ pub mod builtin { /// Includes a file as a reference to a byte array. /// + /// The file is located relative to the current file. (similarly to how + /// modules are found) + /// /// This macro will yield an expression of type `&'static [u8; N]` which is - /// the contents of the filename specified. The file is located relative to - /// the current file (similarly to how modules are found), + /// the contents of the file. /// /// # Examples /// @@ -450,9 +456,17 @@ pub mod builtin { #[macro_export] macro_rules! cfg { ($($cfg:tt)*) => ({ /* compiler built-in */ }) } - /// Parse the current given file as an expression. + /// Parse a file as an expression or an item according to the context. + /// + /// The file is located relative to the current file. (similarly to how + /// modules are found) /// - /// This is generally a bad idea, because it's going to behave unhygienically. + /// Using this macro is often a bad idea, because if the file is + /// parsed as an expression, it is going to be placed in the + /// surrounding code unhygenically. This could result in variables + /// or functions being different from what the file expected if + /// there are variables or functions that have the same name in + /// the current file. /// /// # Examples /// diff --git a/src/libstd/memchr.rs b/src/libstd/memchr.rs index 03f55f7ad6..7c8c97a6ca 100644 --- a/src/libstd/memchr.rs +++ b/src/libstd/memchr.rs @@ -11,8 +11,6 @@ // Original implementation taken from rust-memchr // Copyright 2015 Andrew Gallant, bluss and Nicolas Koch - - /// A safe interface to `memchr`. /// /// Returns the index corresponding to the first occurrence of `needle` in @@ -32,32 +30,9 @@ /// let haystack = b"the quick brown fox"; /// assert_eq!(memchr(b'k', haystack), Some(8)); /// ``` +#[inline] pub fn memchr(needle: u8, haystack: &[u8]) -> Option { - // libc memchr - #[cfg(not(target_os = "windows"))] - fn memchr_specific(needle: u8, haystack: &[u8]) -> Option { - use libc; - - let p = unsafe { - libc::memchr( - haystack.as_ptr() as *const libc::c_void, - needle as libc::c_int, - haystack.len() as libc::size_t) - }; - if p.is_null() { - None - } else { - Some(p as usize - (haystack.as_ptr() as usize)) - } - } - - // use fallback on windows, since it's faster - #[cfg(target_os = "windows")] - fn memchr_specific(needle: u8, haystack: &[u8]) -> Option { - fallback::memchr(needle, haystack) - } - - memchr_specific(needle, haystack) + ::sys::memchr::memchr(needle, haystack) } /// A safe interface to `memrchr`. @@ -75,251 +50,9 @@ pub fn memchr(needle: u8, haystack: &[u8]) -> Option { /// let haystack = b"the quick brown fox"; /// assert_eq!(memrchr(b'o', haystack), Some(17)); /// ``` +#[inline] pub fn memrchr(needle: u8, haystack: &[u8]) -> Option { - - #[cfg(target_os = "linux")] - fn memrchr_specific(needle: u8, haystack: &[u8]) -> Option { - use libc; - - // GNU's memrchr() will - unlike memchr() - error if haystack is empty. - if haystack.is_empty() {return None} - let p = unsafe { - libc::memrchr( - haystack.as_ptr() as *const libc::c_void, - needle as libc::c_int, - haystack.len() as libc::size_t) - }; - if p.is_null() { - None - } else { - Some(p as usize - (haystack.as_ptr() as usize)) - } - } - - #[cfg(not(target_os = "linux"))] - fn memrchr_specific(needle: u8, haystack: &[u8]) -> Option { - fallback::memrchr(needle, haystack) - } - - memrchr_specific(needle, haystack) -} - -#[allow(dead_code)] -mod fallback { - use cmp; - use mem; - - const LO_U64: u64 = 0x0101010101010101; - const HI_U64: u64 = 0x8080808080808080; - - // use truncation - const LO_USIZE: usize = LO_U64 as usize; - const HI_USIZE: usize = HI_U64 as usize; - - /// Return `true` if `x` contains any zero byte. - /// - /// From *Matters Computational*, J. Arndt - /// - /// "The idea is to subtract one from each of the bytes and then look for - /// bytes where the borrow propagated all the way to the most significant - /// bit." - #[inline] - fn contains_zero_byte(x: usize) -> bool { - x.wrapping_sub(LO_USIZE) & !x & HI_USIZE != 0 - } - - #[cfg(target_pointer_width = "32")] - #[inline] - fn repeat_byte(b: u8) -> usize { - let mut rep = (b as usize) << 8 | b as usize; - rep = rep << 16 | rep; - rep - } - - #[cfg(target_pointer_width = "64")] - #[inline] - fn repeat_byte(b: u8) -> usize { - let mut rep = (b as usize) << 8 | b as usize; - rep = rep << 16 | rep; - rep = rep << 32 | rep; - rep - } - - /// Return the first index matching the byte `a` in `text`. - pub fn memchr(x: u8, text: &[u8]) -> Option { - // Scan for a single byte value by reading two `usize` words at a time. - // - // Split `text` in three parts - // - unaligned initial part, before the first word aligned address in text - // - body, scan by 2 words at a time - // - the last remaining part, < 2 word size - let len = text.len(); - let ptr = text.as_ptr(); - let usize_bytes = mem::size_of::(); - - // search up to an aligned boundary - let align = (ptr as usize) & (usize_bytes- 1); - let mut offset; - if align > 0 { - offset = cmp::min(usize_bytes - align, len); - if let Some(index) = text[..offset].iter().position(|elt| *elt == x) { - return Some(index); - } - } else { - offset = 0; - } - - // search the body of the text - let repeated_x = repeat_byte(x); - - if len >= 2 * usize_bytes { - while offset <= len - 2 * usize_bytes { - unsafe { - let u = *(ptr.offset(offset as isize) as *const usize); - let v = *(ptr.offset((offset + usize_bytes) as isize) as *const usize); - - // break if there is a matching byte - let zu = contains_zero_byte(u ^ repeated_x); - let zv = contains_zero_byte(v ^ repeated_x); - if zu || zv { - break; - } - } - offset += usize_bytes * 2; - } - } - - // find the byte after the point the body loop stopped - text[offset..].iter().position(|elt| *elt == x).map(|i| offset + i) - } - - /// Return the last index matching the byte `a` in `text`. - pub fn memrchr(x: u8, text: &[u8]) -> Option { - // Scan for a single byte value by reading two `usize` words at a time. - // - // Split `text` in three parts - // - unaligned tail, after the last word aligned address in text - // - body, scan by 2 words at a time - // - the first remaining bytes, < 2 word size - let len = text.len(); - let ptr = text.as_ptr(); - let usize_bytes = mem::size_of::(); - - // search to an aligned boundary - let end_align = (ptr as usize + len) & (usize_bytes - 1); - let mut offset; - if end_align > 0 { - offset = if end_align >= len { 0 } else { len - end_align }; - if let Some(index) = text[offset..].iter().rposition(|elt| *elt == x) { - return Some(offset + index); - } - } else { - offset = len; - } - - // search the body of the text - let repeated_x = repeat_byte(x); - - while offset >= 2 * usize_bytes { - unsafe { - let u = *(ptr.offset(offset as isize - 2 * usize_bytes as isize) as *const usize); - let v = *(ptr.offset(offset as isize - usize_bytes as isize) as *const usize); - - // break if there is a matching byte - let zu = contains_zero_byte(u ^ repeated_x); - let zv = contains_zero_byte(v ^ repeated_x); - if zu || zv { - break; - } - } - offset -= 2 * usize_bytes; - } - - // find the byte before the point the body loop stopped - text[..offset].iter().rposition(|elt| *elt == x) - } - - // test fallback implementations on all platforms - #[test] - fn matches_one() { - assert_eq!(Some(0), memchr(b'a', b"a")); - } - - #[test] - fn matches_begin() { - assert_eq!(Some(0), memchr(b'a', b"aaaa")); - } - - #[test] - fn matches_end() { - assert_eq!(Some(4), memchr(b'z', b"aaaaz")); - } - - #[test] - fn matches_nul() { - assert_eq!(Some(4), memchr(b'\x00', b"aaaa\x00")); - } - - #[test] - fn matches_past_nul() { - assert_eq!(Some(5), memchr(b'z', b"aaaa\x00z")); - } - - #[test] - fn no_match_empty() { - assert_eq!(None, memchr(b'a', b"")); - } - - #[test] - fn no_match() { - assert_eq!(None, memchr(b'a', b"xyz")); - } - - #[test] - fn matches_one_reversed() { - assert_eq!(Some(0), memrchr(b'a', b"a")); - } - - #[test] - fn matches_begin_reversed() { - assert_eq!(Some(3), memrchr(b'a', b"aaaa")); - } - - #[test] - fn matches_end_reversed() { - assert_eq!(Some(0), memrchr(b'z', b"zaaaa")); - } - - #[test] - fn matches_nul_reversed() { - assert_eq!(Some(4), memrchr(b'\x00', b"aaaa\x00")); - } - - #[test] - fn matches_past_nul_reversed() { - assert_eq!(Some(0), memrchr(b'z', b"z\x00aaaa")); - } - - #[test] - fn no_match_empty_reversed() { - assert_eq!(None, memrchr(b'a', b"")); - } - - #[test] - fn no_match_reversed() { - assert_eq!(None, memrchr(b'a', b"xyz")); - } - - #[test] - fn each_alignment_reversed() { - let mut data = [1u8; 64]; - let needle = 2; - let pos = 40; - data[pos] = needle; - for start in 0..16 { - assert_eq!(Some(pos - start), memrchr(needle, &data[start..])); - } - } + ::sys::memchr::memrchr(needle, haystack) } #[cfg(test)] diff --git a/src/libstd/net/addr.rs b/src/libstd/net/addr.rs index d0b59b42c1..20dc5b3801 100644 --- a/src/libstd/net/addr.rs +++ b/src/libstd/net/addr.rs @@ -93,6 +93,26 @@ impl SocketAddr { SocketAddr::V6(ref mut a) => a.set_port(new_port), } } + + /// Returns true if the IP in this `SocketAddr` is a valid IPv4 address, + /// false if it's a valid IPv6 address. + #[unstable(feature = "sockaddr_checker", issue = "36949")] + pub fn is_ipv4(&self) -> bool { + match *self { + SocketAddr::V4(_) => true, + SocketAddr::V6(_) => false, + } + } + + /// Returns true if the IP in this `SocketAddr` is a valid IPv6 address, + /// false if it's a valid IPv4 address. + #[unstable(feature = "sockaddr_checker", issue = "36949")] + pub fn is_ipv6(&self) -> bool { + match *self { + SocketAddr::V4(_) => false, + SocketAddr::V6(_) => true, + } + } } impl SocketAddrV4 { @@ -519,7 +539,7 @@ impl<'a, T: ToSocketAddrs + ?Sized> ToSocketAddrs for &'a T { } } -#[cfg(test)] +#[cfg(all(test, not(target_os = "emscripten")))] mod tests { use net::*; use net::test::{tsa, sa6, sa4}; @@ -631,4 +651,19 @@ mod tests { v6.set_scope_id(20); assert_eq!(v6.scope_id(), 20); } + + #[test] + fn is_v4() { + let v4 = SocketAddr::V4(SocketAddrV4::new(Ipv4Addr::new(77, 88, 21, 11), 80)); + assert!(v4.is_ipv4()); + assert!(!v4.is_ipv6()); + } + + #[test] + fn is_v6() { + let v6 = SocketAddr::V6(SocketAddrV6::new( + Ipv6Addr::new(0x2a02, 0x6b8, 0, 1, 0, 0, 0, 1), 80, 10, 0)); + assert!(!v6.is_ipv4()); + assert!(v6.is_ipv6()); + } } diff --git a/src/libstd/net/ip.rs b/src/libstd/net/ip.rs index 05ef559422..49080680fa 100644 --- a/src/libstd/net/ip.rs +++ b/src/libstd/net/ip.rs @@ -130,6 +130,24 @@ impl IpAddr { IpAddr::V6(ref a) => a.is_documentation(), } } + + /// Returns true if this address is a valid IPv4 address, false if it's a valid IPv6 address. + #[unstable(feature = "ipaddr_checker", issue = "36949")] + pub fn is_ipv4(&self) -> bool { + match *self { + IpAddr::V4(_) => true, + IpAddr::V6(_) => false, + } + } + + /// Returns true if this address is a valid IPv6 address, false if it's a valid IPv4 address. + #[unstable(feature = "ipaddr_checker", issue = "36949")] + pub fn is_ipv6(&self) -> bool { + match *self { + IpAddr::V4(_) => false, + IpAddr::V6(_) => true, + } + } } impl Ipv4Addr { @@ -277,8 +295,7 @@ impl Ipv4Addr { } } -#[stable(feature = "rust1", since = "1.0.0")] -#[allow(deprecated)] +#[stable(feature = "ip_addr", since = "1.7.0")] impl fmt::Display for IpAddr { fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result { match *self { @@ -669,7 +686,7 @@ impl From<[u8; 16]> for Ipv6Addr { } // Tests for this module -#[cfg(test)] +#[cfg(all(test, not(target_os = "emscripten")))] mod tests { use net::*; use net::Ipv6MulticastScope::*; @@ -1023,4 +1040,18 @@ mod tests { assert!("2001:db8:f00::1002".parse::().unwrap() < "2001:db8:f00::2001".parse::().unwrap()); } + + #[test] + fn is_v4() { + let ip = IpAddr::V4(Ipv4Addr::new(100, 64, 3, 3)); + assert!(ip.is_ipv4()); + assert!(!ip.is_ipv6()); + } + + #[test] + fn is_v6() { + let ip = IpAddr::V6(Ipv6Addr::new(0, 0, 0, 0, 0, 0xffff, 0x1234, 0x5678)); + assert!(!ip.is_ipv4()); + assert!(ip.is_ipv6()); + } } diff --git a/src/libstd/net/mod.rs b/src/libstd/net/mod.rs index ad2fe3c1c0..56286fbe25 100644 --- a/src/libstd/net/mod.rs +++ b/src/libstd/net/mod.rs @@ -31,7 +31,8 @@ mod addr; mod tcp; mod udp; mod parser; -#[cfg(test)] mod test; +#[cfg(test)] +mod test; /// Possible values which can be passed to the [`shutdown`] method of /// [`TcpStream`]. diff --git a/src/libstd/net/parser.rs b/src/libstd/net/parser.rs index ed4af471f2..d86711c10a 100644 --- a/src/libstd/net/parser.rs +++ b/src/libstd/net/parser.rs @@ -302,7 +302,7 @@ impl<'a> Parser<'a> { } } -#[stable(feature = "rust1", since = "1.0.0")] +#[stable(feature = "ip_addr", since = "1.7.0")] impl FromStr for IpAddr { type Err = AddrParseError; fn from_str(s: &str) -> Result { diff --git a/src/libstd/net/tcp.rs b/src/libstd/net/tcp.rs index 3c5f07c3e3..0e7c5b0671 100644 --- a/src/libstd/net/tcp.rs +++ b/src/libstd/net/tcp.rs @@ -428,7 +428,7 @@ impl fmt::Debug for TcpListener { } } -#[cfg(test)] +#[cfg(all(test, not(target_os = "emscripten")))] mod tests { use io::ErrorKind; use io::prelude::*; diff --git a/src/libstd/net/test.rs b/src/libstd/net/test.rs index 98ac61f646..3f2eacda7d 100644 --- a/src/libstd/net/test.rs +++ b/src/libstd/net/test.rs @@ -8,6 +8,8 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. +#[allow(dead_code)] // not used on emscripten + use env; use net::{SocketAddr, SocketAddrV4, SocketAddrV6, Ipv4Addr, Ipv6Addr, ToSocketAddrs}; use sync::atomic::{AtomicUsize, Ordering}; diff --git a/src/libstd/net/udp.rs b/src/libstd/net/udp.rs index 781f026c12..c03ac496ad 100644 --- a/src/libstd/net/udp.rs +++ b/src/libstd/net/udp.rs @@ -353,7 +353,7 @@ impl fmt::Debug for UdpSocket { } } -#[cfg(test)] +#[cfg(all(test, not(target_os = "emscripten")))] mod tests { use io::ErrorKind; use net::*; diff --git a/src/libstd/num/mod.rs b/src/libstd/num.rs similarity index 100% rename from src/libstd/num/mod.rs rename to src/libstd/num.rs diff --git a/src/libstd/os/fuchsia/fs.rs b/src/libstd/os/fuchsia/fs.rs new file mode 100644 index 0000000000..d22f9a628b --- /dev/null +++ b/src/libstd/os/fuchsia/fs.rs @@ -0,0 +1,103 @@ +// Copyright 2016 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +#![stable(feature = "metadata_ext", since = "1.1.0")] + +use fs::Metadata; +use sys_common::AsInner; + +/// OS-specific extension methods for `fs::Metadata` +#[stable(feature = "metadata_ext", since = "1.1.0")] +pub trait MetadataExt { + #[stable(feature = "metadata_ext2", since = "1.8.0")] + fn st_dev(&self) -> u64; + #[stable(feature = "metadata_ext2", since = "1.8.0")] + fn st_ino(&self) -> u64; + #[stable(feature = "metadata_ext2", since = "1.8.0")] + fn st_mode(&self) -> u32; + #[stable(feature = "metadata_ext2", since = "1.8.0")] + fn st_nlink(&self) -> u64; + #[stable(feature = "metadata_ext2", since = "1.8.0")] + fn st_uid(&self) -> u32; + #[stable(feature = "metadata_ext2", since = "1.8.0")] + fn st_gid(&self) -> u32; + #[stable(feature = "metadata_ext2", since = "1.8.0")] + fn st_rdev(&self) -> u64; + #[stable(feature = "metadata_ext2", since = "1.8.0")] + fn st_size(&self) -> u64; + #[stable(feature = "metadata_ext2", since = "1.8.0")] + fn st_atime(&self) -> i64; + #[stable(feature = "metadata_ext2", since = "1.8.0")] + fn st_atime_nsec(&self) -> i64; + #[stable(feature = "metadata_ext2", since = "1.8.0")] + fn st_mtime(&self) -> i64; + #[stable(feature = "metadata_ext2", since = "1.8.0")] + fn st_mtime_nsec(&self) -> i64; + #[stable(feature = "metadata_ext2", since = "1.8.0")] + fn st_ctime(&self) -> i64; + #[stable(feature = "metadata_ext2", since = "1.8.0")] + fn st_ctime_nsec(&self) -> i64; + #[stable(feature = "metadata_ext2", since = "1.8.0")] + fn st_blksize(&self) -> u64; + #[stable(feature = "metadata_ext2", since = "1.8.0")] + fn st_blocks(&self) -> u64; +} + +#[stable(feature = "metadata_ext", since = "1.1.0")] +impl MetadataExt for Metadata { + fn st_dev(&self) -> u64 { + self.as_inner().as_inner().st_dev as u64 + } + fn st_ino(&self) -> u64 { + self.as_inner().as_inner().st_ino as u64 + } + fn st_mode(&self) -> u32 { + self.as_inner().as_inner().st_mode as u32 + } + fn st_nlink(&self) -> u64 { + self.as_inner().as_inner().st_nlink as u64 + } + fn st_uid(&self) -> u32 { + self.as_inner().as_inner().st_uid as u32 + } + fn st_gid(&self) -> u32 { + self.as_inner().as_inner().st_gid as u32 + } + fn st_rdev(&self) -> u64 { + self.as_inner().as_inner().st_rdev as u64 + } + fn st_size(&self) -> u64 { + self.as_inner().as_inner().st_size as u64 + } + fn st_atime(&self) -> i64 { + self.as_inner().as_inner().st_atime as i64 + } + fn st_atime_nsec(&self) -> i64 { + self.as_inner().as_inner().st_atime_nsec as i64 + } + fn st_mtime(&self) -> i64 { + self.as_inner().as_inner().st_mtime as i64 + } + fn st_mtime_nsec(&self) -> i64 { + self.as_inner().as_inner().st_mtime_nsec as i64 + } + fn st_ctime(&self) -> i64 { + self.as_inner().as_inner().st_ctime as i64 + } + fn st_ctime_nsec(&self) -> i64 { + self.as_inner().as_inner().st_ctime_nsec as i64 + } + fn st_blksize(&self) -> u64 { + self.as_inner().as_inner().st_blksize as u64 + } + fn st_blocks(&self) -> u64 { + self.as_inner().as_inner().st_blocks as u64 + } +} diff --git a/src/libstd/os/fuchsia/mod.rs b/src/libstd/os/fuchsia/mod.rs new file mode 100644 index 0000000000..1ebcbba914 --- /dev/null +++ b/src/libstd/os/fuchsia/mod.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. + +//! Fuchsia-specific definitions + +#![stable(feature = "raw_ext", since = "1.1.0")] + +pub mod raw; +pub mod fs; diff --git a/src/libstd/os/fuchsia/raw.rs b/src/libstd/os/fuchsia/raw.rs new file mode 100644 index 0000000000..5d01735149 --- /dev/null +++ b/src/libstd/os/fuchsia/raw.rs @@ -0,0 +1,270 @@ +// 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. + +//! Fuchsia-specific raw type definitions + +#![stable(feature = "raw_ext", since = "1.1.0")] +#![rustc_deprecated(since = "1.8.0", + reason = "these type aliases are no longer supported by \ + the standard library, the `libc` crate on \ + crates.io should be used instead for the correct \ + definitions")] +#![allow(deprecated)] + +use os::raw::c_ulong; + +#[stable(feature = "raw_ext", since = "1.1.0")] pub type dev_t = u64; +#[stable(feature = "raw_ext", since = "1.1.0")] pub type mode_t = u32; + +#[stable(feature = "pthread_t", since = "1.8.0")] +pub type pthread_t = c_ulong; + +#[doc(inline)] +#[stable(feature = "raw_ext", since = "1.1.0")] +pub use self::arch::{off_t, ino_t, nlink_t, blksize_t, blkcnt_t, stat, time_t}; + +#[cfg(any(target_arch = "x86", + target_arch = "le32", + target_arch = "powerpc", + target_arch = "arm"))] +mod arch { + use os::raw::{c_long, c_short, c_uint}; + + #[stable(feature = "raw_ext", since = "1.1.0")] pub type blkcnt_t = u64; + #[stable(feature = "raw_ext", since = "1.1.0")] pub type blksize_t = u64; + #[stable(feature = "raw_ext", since = "1.1.0")] pub type ino_t = u64; + #[stable(feature = "raw_ext", since = "1.1.0")] pub type nlink_t = u64; + #[stable(feature = "raw_ext", since = "1.1.0")] pub type off_t = u64; + #[stable(feature = "raw_ext", since = "1.1.0")] pub type time_t = i64; + + #[repr(C)] + #[derive(Clone)] + #[stable(feature = "raw_ext", since = "1.1.0")] + pub struct stat { + #[stable(feature = "raw_ext", since = "1.1.0")] + pub st_dev: u64, + #[stable(feature = "raw_ext", since = "1.1.0")] + pub __pad1: c_short, + #[stable(feature = "raw_ext", since = "1.1.0")] + pub __st_ino: u32, + #[stable(feature = "raw_ext", since = "1.1.0")] + pub st_mode: u32, + #[stable(feature = "raw_ext", since = "1.1.0")] + pub st_nlink: u32, + #[stable(feature = "raw_ext", since = "1.1.0")] + pub st_uid: u32, + #[stable(feature = "raw_ext", since = "1.1.0")] + pub st_gid: u32, + #[stable(feature = "raw_ext", since = "1.1.0")] + pub st_rdev: u64, + #[stable(feature = "raw_ext", since = "1.1.0")] + pub __pad2: c_uint, + #[stable(feature = "raw_ext", since = "1.1.0")] + pub st_size: i64, + #[stable(feature = "raw_ext", since = "1.1.0")] + pub st_blksize: i32, + #[stable(feature = "raw_ext", since = "1.1.0")] + pub st_blocks: i64, + #[stable(feature = "raw_ext", since = "1.1.0")] + pub st_atime: i32, + #[stable(feature = "raw_ext", since = "1.1.0")] + pub st_atime_nsec: c_long, + #[stable(feature = "raw_ext", since = "1.1.0")] + pub st_mtime: i32, + #[stable(feature = "raw_ext", since = "1.1.0")] + pub st_mtime_nsec: c_long, + #[stable(feature = "raw_ext", since = "1.1.0")] + pub st_ctime: i32, + #[stable(feature = "raw_ext", since = "1.1.0")] + pub st_ctime_nsec: c_long, + #[stable(feature = "raw_ext", since = "1.1.0")] + pub st_ino: u64, + } +} + +#[cfg(target_arch = "mips")] +mod arch { + use os::raw::{c_long, c_ulong}; + + #[cfg(target_env = "musl")] + #[stable(feature = "raw_ext", since = "1.1.0")] pub type blkcnt_t = i64; + #[cfg(not(target_env = "musl"))] + #[stable(feature = "raw_ext", since = "1.1.0")] pub type blkcnt_t = u64; + #[stable(feature = "raw_ext", since = "1.1.0")] pub type blksize_t = u64; + #[cfg(target_env = "musl")] + #[stable(feature = "raw_ext", since = "1.1.0")] pub type ino_t = u64; + #[cfg(not(target_env = "musl"))] + #[stable(feature = "raw_ext", since = "1.1.0")] pub type ino_t = u64; + #[stable(feature = "raw_ext", since = "1.1.0")] pub type nlink_t = u64; + #[cfg(target_env = "musl")] + #[stable(feature = "raw_ext", since = "1.1.0")] pub type off_t = u64; + #[cfg(not(target_env = "musl"))] + #[stable(feature = "raw_ext", since = "1.1.0")] pub type off_t = u64; + #[stable(feature = "raw_ext", since = "1.1.0")] pub type time_t = i64; + + #[repr(C)] + #[derive(Clone)] + #[stable(feature = "raw_ext", since = "1.1.0")] + pub struct stat { + #[stable(feature = "raw_ext", since = "1.1.0")] + pub st_dev: c_ulong, + #[stable(feature = "raw_ext", since = "1.1.0")] + pub st_pad1: [c_long; 3], + #[stable(feature = "raw_ext", since = "1.1.0")] + pub st_ino: u64, + #[stable(feature = "raw_ext", since = "1.1.0")] + pub st_mode: u32, + #[stable(feature = "raw_ext", since = "1.1.0")] + pub st_nlink: u32, + #[stable(feature = "raw_ext", since = "1.1.0")] + pub st_uid: u32, + #[stable(feature = "raw_ext", since = "1.1.0")] + pub st_gid: u32, + #[stable(feature = "raw_ext", since = "1.1.0")] + pub st_rdev: c_ulong, + #[stable(feature = "raw_ext", since = "1.1.0")] + pub st_pad2: [c_long; 2], + #[stable(feature = "raw_ext", since = "1.1.0")] + pub st_size: i64, + #[stable(feature = "raw_ext", since = "1.1.0")] + pub st_atime: i32, + #[stable(feature = "raw_ext", since = "1.1.0")] + pub st_atime_nsec: c_long, + #[stable(feature = "raw_ext", since = "1.1.0")] + pub st_mtime: i32, + #[stable(feature = "raw_ext", since = "1.1.0")] + pub st_mtime_nsec: c_long, + #[stable(feature = "raw_ext", since = "1.1.0")] + pub st_ctime: i32, + #[stable(feature = "raw_ext", since = "1.1.0")] + pub st_ctime_nsec: c_long, + #[stable(feature = "raw_ext", since = "1.1.0")] + pub st_blksize: i32, + #[stable(feature = "raw_ext", since = "1.1.0")] + pub st_blocks: i64, + #[stable(feature = "raw_ext", since = "1.1.0")] + pub st_pad5: [c_long; 14], + } +} + +#[cfg(target_arch = "mips64")] +mod arch { + pub use libc::{off_t, ino_t, nlink_t, blksize_t, blkcnt_t, stat, time_t}; +} + +#[cfg(target_arch = "aarch64")] +mod arch { + use os::raw::{c_long, c_int}; + + #[stable(feature = "raw_ext", since = "1.1.0")] pub type blkcnt_t = u64; + #[stable(feature = "raw_ext", since = "1.1.0")] pub type blksize_t = u64; + #[stable(feature = "raw_ext", since = "1.1.0")] pub type ino_t = u64; + #[stable(feature = "raw_ext", since = "1.1.0")] pub type nlink_t = u64; + #[stable(feature = "raw_ext", since = "1.1.0")] pub type off_t = u64; + #[stable(feature = "raw_ext", since = "1.1.0")] pub type time_t = i64; + + #[repr(C)] + #[derive(Clone)] + #[stable(feature = "raw_ext", since = "1.1.0")] + pub struct stat { + #[stable(feature = "raw_ext", since = "1.1.0")] + pub st_dev: u64, + #[stable(feature = "raw_ext", since = "1.1.0")] + pub st_ino: u64, + #[stable(feature = "raw_ext", since = "1.1.0")] + pub st_mode: u32, + #[stable(feature = "raw_ext", since = "1.1.0")] + pub st_nlink: u32, + #[stable(feature = "raw_ext", since = "1.1.0")] + pub st_uid: u32, + #[stable(feature = "raw_ext", since = "1.1.0")] + pub st_gid: u32, + #[stable(feature = "raw_ext", since = "1.1.0")] + pub st_rdev: u64, + #[stable(feature = "raw_ext", since = "1.1.0")] + pub __pad1: u64, + #[stable(feature = "raw_ext", since = "1.1.0")] + pub st_size: i64, + #[stable(feature = "raw_ext", since = "1.1.0")] + pub st_blksize: i32, + #[stable(feature = "raw_ext", since = "1.1.0")] + pub __pad2: c_int, + #[stable(feature = "raw_ext", since = "1.1.0")] + pub st_blocks: i64, + #[stable(feature = "raw_ext", since = "1.1.0")] + pub st_atime: i64, + #[stable(feature = "raw_ext", since = "1.1.0")] + pub st_atime_nsec: c_long, + #[stable(feature = "raw_ext", since = "1.1.0")] + pub st_mtime: i64, + #[stable(feature = "raw_ext", since = "1.1.0")] + pub st_mtime_nsec: c_long, + #[stable(feature = "raw_ext", since = "1.1.0")] + pub st_ctime: i64, + #[stable(feature = "raw_ext", since = "1.1.0")] + pub st_ctime_nsec: c_long, + #[stable(feature = "raw_ext", since = "1.1.0")] + pub __unused: [c_int; 2], + } +} + +#[cfg(target_arch = "x86_64")] +mod arch { + use os::raw::{c_long, c_int}; + + #[stable(feature = "raw_ext", since = "1.1.0")] pub type blkcnt_t = u64; + #[stable(feature = "raw_ext", since = "1.1.0")] pub type blksize_t = u64; + #[stable(feature = "raw_ext", since = "1.1.0")] pub type ino_t = u64; + #[stable(feature = "raw_ext", since = "1.1.0")] pub type nlink_t = u64; + #[stable(feature = "raw_ext", since = "1.1.0")] pub type off_t = u64; + #[stable(feature = "raw_ext", since = "1.1.0")] pub type time_t = i64; + + #[repr(C)] + #[derive(Clone)] + #[stable(feature = "raw_ext", since = "1.1.0")] + pub struct stat { + #[stable(feature = "raw_ext", since = "1.1.0")] + pub st_dev: u64, + #[stable(feature = "raw_ext", since = "1.1.0")] + pub st_ino: u64, + #[stable(feature = "raw_ext", since = "1.1.0")] + pub st_nlink: u64, + #[stable(feature = "raw_ext", since = "1.1.0")] + pub st_mode: u32, + #[stable(feature = "raw_ext", since = "1.1.0")] + pub st_uid: u32, + #[stable(feature = "raw_ext", since = "1.1.0")] + pub st_gid: u32, + #[stable(feature = "raw_ext", since = "1.1.0")] + pub __pad0: c_int, + #[stable(feature = "raw_ext", since = "1.1.0")] + pub st_rdev: u64, + #[stable(feature = "raw_ext", since = "1.1.0")] + pub st_size: i64, + #[stable(feature = "raw_ext", since = "1.1.0")] + pub st_blksize: i64, + #[stable(feature = "raw_ext", since = "1.1.0")] + pub st_blocks: i64, + #[stable(feature = "raw_ext", since = "1.1.0")] + pub st_atime: i64, + #[stable(feature = "raw_ext", since = "1.1.0")] + pub st_atime_nsec: c_long, + #[stable(feature = "raw_ext", since = "1.1.0")] + pub st_mtime: i64, + #[stable(feature = "raw_ext", since = "1.1.0")] + pub st_mtime_nsec: c_long, + #[stable(feature = "raw_ext", since = "1.1.0")] + pub st_ctime: i64, + #[stable(feature = "raw_ext", since = "1.1.0")] + pub st_ctime_nsec: c_long, + #[stable(feature = "raw_ext", since = "1.1.0")] + pub __unused: [c_long; 3], + } +} diff --git a/src/libstd/os/linux/raw.rs b/src/libstd/os/linux/raw.rs index 1c19e58818..e6a95bc831 100644 --- a/src/libstd/os/linux/raw.rs +++ b/src/libstd/os/linux/raw.rs @@ -34,7 +34,8 @@ pub use self::arch::{off_t, ino_t, nlink_t, blksize_t, blkcnt_t, stat, time_t}; target_arch = "le32", target_arch = "powerpc", target_arch = "arm", - target_arch = "asmjs"))] + target_arch = "asmjs", + target_arch = "wasm32"))] mod arch { use os::raw::{c_long, c_short, c_uint}; diff --git a/src/libstd/os/mod.rs b/src/libstd/os/mod.rs index 7622ef8869..366a167415 100644 --- a/src/libstd/os/mod.rs +++ b/src/libstd/os/mod.rs @@ -33,5 +33,6 @@ pub use sys::ext as windows; #[cfg(target_os = "openbsd")] pub mod openbsd; #[cfg(target_os = "solaris")] pub mod solaris; #[cfg(target_os = "emscripten")] pub mod emscripten; +#[cfg(target_os = "fuchsia")] pub mod fuchsia; pub mod raw; diff --git a/src/libstd/os/raw.rs b/src/libstd/os/raw.rs index 6c5c1b90a4..2a918d8aeb 100644 --- a/src/libstd/os/raw.rs +++ b/src/libstd/os/raw.rs @@ -18,7 +18,8 @@ target_arch = "arm", target_arch = "powerpc", target_arch = "powerpc64", - target_arch = "s390x"))))] + target_arch = "s390x")), + all(target_os = "fuchsia", target_arch = "aarch64")))] #[stable(feature = "raw_os", since = "1.1.0")] pub type c_char = u8; #[cfg(not(any(target_os = "android", target_os = "emscripten", @@ -26,7 +27,8 @@ target_arch = "arm", target_arch = "powerpc", target_arch = "powerpc64", - target_arch = "s390x")))))] + target_arch = "s390x")), + all(target_os = "fuchsia", target_arch = "aarch64"))))] #[stable(feature = "raw_os", since = "1.1.0")] pub type c_char = i8; #[stable(feature = "raw_os", since = "1.1.0")] pub type c_schar = i8; #[stable(feature = "raw_os", since = "1.1.0")] pub type c_uchar = u8; diff --git a/src/libstd/panic.rs b/src/libstd/panic.rs index 47f594a9b0..a7e8c4fab3 100644 --- a/src/libstd/panic.rs +++ b/src/libstd/panic.rs @@ -18,7 +18,7 @@ use ops::{Deref, DerefMut}; use panicking; use ptr::{Unique, Shared}; use rc::Rc; -use sync::{Arc, Mutex, RwLock}; +use sync::{Arc, Mutex, RwLock, atomic}; use thread::Result; #[stable(feature = "panic_hooks", since = "1.10.0")] @@ -196,9 +196,9 @@ impl<'a, T: RefUnwindSafe + ?Sized> UnwindSafe for &'a T {} impl UnwindSafe for *const T {} #[stable(feature = "catch_unwind", since = "1.9.0")] impl UnwindSafe for *mut T {} -#[stable(feature = "catch_unwind", since = "1.9.0")] +#[unstable(feature = "unique", issue = "27730")] impl UnwindSafe for Unique {} -#[stable(feature = "catch_unwind", since = "1.9.0")] +#[unstable(feature = "shared", issue = "27730")] impl UnwindSafe for Shared {} #[stable(feature = "catch_unwind", since = "1.9.0")] impl UnwindSafe for Mutex {} @@ -231,6 +231,46 @@ impl RefUnwindSafe for Mutex {} #[stable(feature = "unwind_safe_lock_refs", since = "1.12.0")] impl RefUnwindSafe for RwLock {} +#[cfg(target_has_atomic = "ptr")] +#[stable(feature = "unwind_safe_atomic_refs", since = "1.14.0")] +impl RefUnwindSafe for atomic::AtomicIsize {} +#[cfg(target_has_atomic = "8")] +#[unstable(feature = "integer_atomics", issue = "32976")] +impl RefUnwindSafe for atomic::AtomicI8 {} +#[cfg(target_has_atomic = "16")] +#[unstable(feature = "integer_atomics", issue = "32976")] +impl RefUnwindSafe for atomic::AtomicI16 {} +#[cfg(target_has_atomic = "32")] +#[unstable(feature = "integer_atomics", issue = "32976")] +impl RefUnwindSafe for atomic::AtomicI32 {} +#[cfg(target_has_atomic = "64")] +#[unstable(feature = "integer_atomics", issue = "32976")] +impl RefUnwindSafe for atomic::AtomicI64 {} + +#[cfg(target_has_atomic = "ptr")] +#[stable(feature = "unwind_safe_atomic_refs", since = "1.14.0")] +impl RefUnwindSafe for atomic::AtomicUsize {} +#[cfg(target_has_atomic = "8")] +#[unstable(feature = "integer_atomics", issue = "32976")] +impl RefUnwindSafe for atomic::AtomicU8 {} +#[cfg(target_has_atomic = "16")] +#[unstable(feature = "integer_atomics", issue = "32976")] +impl RefUnwindSafe for atomic::AtomicU16 {} +#[cfg(target_has_atomic = "32")] +#[unstable(feature = "integer_atomics", issue = "32976")] +impl RefUnwindSafe for atomic::AtomicU32 {} +#[cfg(target_has_atomic = "64")] +#[unstable(feature = "integer_atomics", issue = "32976")] +impl RefUnwindSafe for atomic::AtomicU64 {} + +#[cfg(target_has_atomic = "8")] +#[stable(feature = "unwind_safe_atomic_refs", since = "1.14.0")] +impl RefUnwindSafe for atomic::AtomicBool {} + +#[cfg(target_has_atomic = "ptr")] +#[stable(feature = "unwind_safe_atomic_refs", since = "1.14.0")] +impl RefUnwindSafe for atomic::AtomicPtr {} + #[stable(feature = "catch_unwind", since = "1.9.0")] impl Deref for AssertUnwindSafe { type Target = T; diff --git a/src/libstd/path.rs b/src/libstd/path.rs index d625934133..bb6883236e 100644 --- a/src/libstd/path.rs +++ b/src/libstd/path.rs @@ -113,7 +113,7 @@ use ops::{self, Deref}; use ffi::{OsStr, OsString}; -use self::platform::{is_sep_byte, is_verbatim_sep, MAIN_SEP_STR, parse_prefix}; +use sys::path::{is_sep_byte, is_verbatim_sep, MAIN_SEP_STR, parse_prefix}; //////////////////////////////////////////////////////////////////////////////// // GENERAL NOTES @@ -125,130 +125,6 @@ use self::platform::{is_sep_byte, is_verbatim_sep, MAIN_SEP_STR, parse_prefix}; // OsStr APIs for parsing, but it will take a while for those to become // available. -//////////////////////////////////////////////////////////////////////////////// -// Platform-specific definitions -//////////////////////////////////////////////////////////////////////////////// - -// The following modules give the most basic tools for parsing paths on various -// platforms. The bulk of the code is devoted to parsing prefixes on Windows. - -#[cfg(unix)] -mod platform { - use super::Prefix; - use ffi::OsStr; - - #[inline] - pub fn is_sep_byte(b: u8) -> bool { - b == b'/' - } - - #[inline] - pub fn is_verbatim_sep(b: u8) -> bool { - b == b'/' - } - - pub fn parse_prefix(_: &OsStr) -> Option { - None - } - - pub const MAIN_SEP_STR: &'static str = "/"; - pub const MAIN_SEP: char = '/'; -} - -#[cfg(windows)] -mod platform { - use ascii::*; - - use super::{os_str_as_u8_slice, u8_slice_as_os_str, Prefix}; - use ffi::OsStr; - - #[inline] - pub fn is_sep_byte(b: u8) -> bool { - b == b'/' || b == b'\\' - } - - #[inline] - pub fn is_verbatim_sep(b: u8) -> bool { - b == b'\\' - } - - pub fn parse_prefix<'a>(path: &'a OsStr) -> Option { - use super::Prefix::*; - unsafe { - // The unsafety here stems from converting between &OsStr and &[u8] - // and back. This is safe to do because (1) we only look at ASCII - // contents of the encoding and (2) new &OsStr values are produced - // only from ASCII-bounded slices of existing &OsStr values. - let mut path = os_str_as_u8_slice(path); - - if path.starts_with(br"\\") { - // \\ - path = &path[2..]; - if path.starts_with(br"?\") { - // \\?\ - path = &path[2..]; - if path.starts_with(br"UNC\") { - // \\?\UNC\server\share - path = &path[4..]; - let (server, share) = match parse_two_comps(path, is_verbatim_sep) { - Some((server, share)) => - (u8_slice_as_os_str(server), u8_slice_as_os_str(share)), - None => (u8_slice_as_os_str(path), u8_slice_as_os_str(&[])), - }; - return Some(VerbatimUNC(server, share)); - } else { - // \\?\path - let idx = path.iter().position(|&b| b == b'\\'); - if idx == Some(2) && path[1] == b':' { - let c = path[0]; - if c.is_ascii() && (c as char).is_alphabetic() { - // \\?\C:\ path - return Some(VerbatimDisk(c.to_ascii_uppercase())); - } - } - let slice = &path[..idx.unwrap_or(path.len())]; - return Some(Verbatim(u8_slice_as_os_str(slice))); - } - } else if path.starts_with(b".\\") { - // \\.\path - path = &path[2..]; - let pos = path.iter().position(|&b| b == b'\\'); - let slice = &path[..pos.unwrap_or(path.len())]; - return Some(DeviceNS(u8_slice_as_os_str(slice))); - } - match parse_two_comps(path, is_sep_byte) { - 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))); - } - _ => (), - } - } else if path.get(1) == Some(& b':') { - // C: - let c = path[0]; - if c.is_ascii() && (c as char).is_alphabetic() { - return Some(Disk(c.to_ascii_uppercase())); - } - } - return None; - } - - fn parse_two_comps(mut path: &[u8], f: fn(u8) -> bool) -> Option<(&[u8], &[u8])> { - let first = match path.iter().position(|x| f(*x)) { - None => return None, - Some(x) => &path[..x], - }; - path = &path[(first.len() + 1)..]; - let idx = path.iter().position(|x| f(*x)); - let second = &path[..idx.unwrap_or(path.len())]; - Some((first, second)) - } - } - - pub const MAIN_SEP_STR: &'static str = "\\"; - pub const MAIN_SEP: char = '\\'; -} - //////////////////////////////////////////////////////////////////////////////// // Windows Prefixes //////////////////////////////////////////////////////////////////////////////// @@ -373,7 +249,7 @@ pub fn is_separator(c: char) -> bool { /// The primary separator for the current platform #[stable(feature = "rust1", since = "1.0.0")] -pub const MAIN_SEPARATOR: char = platform::MAIN_SEP; +pub const MAIN_SEPARATOR: char = ::sys::path::MAIN_SEP; //////////////////////////////////////////////////////////////////////////////// // Misc helpers @@ -1038,6 +914,7 @@ impl<'a> cmp::Ord for Components<'a> { /// [`Path`]: struct.Path.html /// [`push`]: struct.PathBuf.html#method.push /// [`set_extension`]: struct.PathBuf.html#method.set_extension +/// [`Deref`]: ../ops/trait.Deref.html /// /// More details about the overall approach can be found in /// the module documentation. @@ -1296,6 +1173,13 @@ impl From for PathBuf { } } +#[stable(feature = "from_path_buf_for_os_string", since = "1.14.0")] +impl From for OsString { + fn from(path_buf : PathBuf) -> OsString { + path_buf.inner + } +} + #[stable(feature = "rust1", since = "1.0.0")] impl From for PathBuf { fn from(s: String) -> PathBuf { @@ -1406,26 +1290,23 @@ impl AsRef for PathBuf { } } -#[stable(feature = "rust1", since = "1.0.0")] -impl Into for PathBuf { - fn into(self) -> OsString { - self.inner - } -} - /// A slice of a path (akin to [`str`]). /// /// This type supports a number of operations for inspecting a path, including /// breaking the path into its components (separated by `/` or `\`, depending on /// the platform), extracting the file name, determining whether the path is -/// absolute, and so on. More details about the overall approach can be found in -/// the module documentation. +/// absolute, and so on. /// /// This is an *unsized* type, meaning that it must always be used behind a -/// pointer like `&` or [`Box`]. +/// pointer like `&` or [`Box`]. For an owned version of this type, +/// see [`PathBuf`]. /// /// [`str`]: ../primitive.str.html /// [`Box`]: ../boxed/struct.Box.html +/// [`PathBuf`]: struct.PathBuf.html +/// +/// More details about the overall approach can be found in +/// the module documentation. /// /// # Examples /// diff --git a/src/libstd/primitive_docs.rs b/src/libstd/primitive_docs.rs index fdc8446701..54dde6681e 100644 --- a/src/libstd/primitive_docs.rs +++ b/src/libstd/primitive_docs.rs @@ -229,7 +229,7 @@ mod prim_unit { } /// /// fn main() { /// unsafe { -/// let my_num: *mut i32 = libc::malloc(mem::size_of::() as libc::size_t) as *mut i32; +/// let my_num: *mut i32 = libc::malloc(mem::size_of::()) as *mut i32; /// if my_num.is_null() { /// panic!("failed to allocate memory"); /// } diff --git a/src/libstd/process.rs b/src/libstd/process.rs index f0c4443070..9d21a76e81 100644 --- a/src/libstd/process.rs +++ b/src/libstd/process.rs @@ -8,7 +8,25 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -//! Working with processes. +//! A module for working with processes. +//! +//! # Examples +//! +//! Basic usage where we try to execute the `cat` shell command: +//! +//! ```should_panic +//! use std::process::Command; +//! +//! let mut child = Command::new("/bin/cat") +//! .arg("file.txt") +//! .spawn() +//! .expect("failed to execute child"); +//! +//! let ecode = child.wait() +//! .expect("failed to wait on child"); +//! +//! assert!(ecode.success()); +//! ``` #![stable(feature = "process", since = "1.0.0")] @@ -807,7 +825,7 @@ pub fn exit(code: i32) -> ! { ::sys::os::exit(code) } -#[cfg(test)] +#[cfg(all(test, not(target_os = "emscripten")))] mod tests { use io::prelude::*; diff --git a/src/libstd/rand/mod.rs b/src/libstd/rand/mod.rs index 3f14fcd239..f48325218f 100644 --- a/src/libstd/rand/mod.rs +++ b/src/libstd/rand/mod.rs @@ -242,9 +242,10 @@ mod tests { } #[test] + #[cfg_attr(target_os = "emscripten", ignore)] fn test_os_rng_tasks() { - let mut txs = vec!(); + let mut txs = vec![]; for _ in 0..20 { let (tx, rx) = channel(); txs.push(tx); diff --git a/src/libstd/rt.rs b/src/libstd/rt.rs index e3de1efaa3..78d5aa597b 100644 --- a/src/libstd/rt.rs +++ b/src/libstd/rt.rs @@ -51,7 +51,7 @@ fn lang_start(main: *const u8, argc: isize, argv: *const *const u8) -> isize { thread_info::set(main_guard, thread); // Store our args if necessary in a squirreled away location - sys_common::args::init(argc, argv); + sys::args::init(argc, argv); // Let's run some code! let res = panic::catch_unwind(mem::transmute::<_, fn()>(main)); diff --git a/src/libstd/sync/barrier.rs b/src/libstd/sync/barrier.rs index ac0f400379..f46eab6848 100644 --- a/src/libstd/sync/barrier.rs +++ b/src/libstd/sync/barrier.rs @@ -118,6 +118,7 @@ mod tests { use thread; #[test] + #[cfg_attr(target_os = "emscripten", ignore)] fn test_barrier() { const N: usize = 10; diff --git a/src/libstd/sync/condvar.rs b/src/libstd/sync/condvar.rs index 3db8b05b95..a983ae716a 100644 --- a/src/libstd/sync/condvar.rs +++ b/src/libstd/sync/condvar.rs @@ -270,6 +270,7 @@ mod tests { } #[test] + #[cfg_attr(target_os = "emscripten", ignore)] fn notify_one() { let m = Arc::new(Mutex::new(())); let m2 = m.clone(); @@ -286,6 +287,7 @@ mod tests { } #[test] + #[cfg_attr(target_os = "emscripten", ignore)] fn notify_all() { const N: usize = 10; @@ -322,6 +324,7 @@ mod tests { } #[test] + #[cfg_attr(target_os = "emscripten", ignore)] fn wait_timeout_ms() { let m = Arc::new(Mutex::new(())); let m2 = m.clone(); @@ -343,6 +346,7 @@ mod tests { #[test] #[should_panic] + #[cfg_attr(target_os = "emscripten", ignore)] fn two_mutexes() { let m = Arc::new(Mutex::new(())); let m2 = m.clone(); diff --git a/src/libstd/sync/mpsc/mod.rs b/src/libstd/sync/mpsc/mod.rs index 00fbe3ad90..fce640e7c7 100644 --- a/src/libstd/sync/mpsc/mod.rs +++ b/src/libstd/sync/mpsc/mod.rs @@ -1267,7 +1267,7 @@ impl error::Error for TryRecvError { } } -#[cfg(test)] +#[cfg(all(test, not(target_os = "emscripten")))] mod tests { use env; use super::*; @@ -1939,9 +1939,16 @@ mod tests { // wait for the child thread to exit before we exit rx2.recv().unwrap(); } + + #[test] + fn issue_32114() { + let (tx, _) = channel(); + let _ = tx.send(123); + assert_eq!(tx.send(123), Err(SendError(123))); + } } -#[cfg(test)] +#[cfg(all(test, not(target_os = "emscripten")))] mod sync_tests { use env; use thread; diff --git a/src/libstd/sync/mpsc/mpsc_queue.rs b/src/libstd/sync/mpsc/mpsc_queue.rs index d926043fbb..8d80f942ff 100644 --- a/src/libstd/sync/mpsc/mpsc_queue.rs +++ b/src/libstd/sync/mpsc/mpsc_queue.rs @@ -146,7 +146,7 @@ impl Drop for Queue { } } -#[cfg(test)] +#[cfg(all(test, not(target_os = "emscripten")))] mod tests { use sync::mpsc::channel; use super::{Queue, Data, Empty, Inconsistent}; diff --git a/src/libstd/sync/mpsc/oneshot.rs b/src/libstd/sync/mpsc/oneshot.rs index 7389280b85..767e9f96ac 100644 --- a/src/libstd/sync/mpsc/oneshot.rs +++ b/src/libstd/sync/mpsc/oneshot.rs @@ -113,6 +113,8 @@ impl Packet { // Couldn't send the data, the port hung up first. Return the data // back up the stack. DISCONNECTED => { + self.state.swap(DISCONNECTED, Ordering::SeqCst); + self.upgrade = NothingSent; Err(self.data.take().unwrap()) } diff --git a/src/libstd/sync/mpsc/select.rs b/src/libstd/sync/mpsc/select.rs index 51b08bd75c..8b4da532af 100644 --- a/src/libstd/sync/mpsc/select.rs +++ b/src/libstd/sync/mpsc/select.rs @@ -352,22 +352,20 @@ impl Iterator for Packets { } } -#[stable(feature = "mpsc_debug", since = "1.7.0")] impl fmt::Debug for Select { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { write!(f, "Select {{ .. }}") } } -#[stable(feature = "mpsc_debug", since = "1.7.0")] impl<'rx, T:Send+'rx> fmt::Debug for Handle<'rx, T> { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { write!(f, "Handle {{ .. }}") } } -#[cfg(test)] #[allow(unused_imports)] +#[cfg(all(test, not(target_os = "emscripten")))] mod tests { use thread; use sync::mpsc::*; diff --git a/src/libstd/sync/mpsc/spsc_queue.rs b/src/libstd/sync/mpsc/spsc_queue.rs index 724d7b1be7..5858e4b6dd 100644 --- a/src/libstd/sync/mpsc/spsc_queue.rs +++ b/src/libstd/sync/mpsc/spsc_queue.rs @@ -231,7 +231,7 @@ impl Drop for Queue { } } -#[cfg(test)] +#[cfg(all(test, not(target_os = "emscripten")))] mod tests { use sync::Arc; use super::Queue; diff --git a/src/libstd/sync/mutex.rs b/src/libstd/sync/mutex.rs index 098a3e4425..812724c7a1 100644 --- a/src/libstd/sync/mutex.rs +++ b/src/libstd/sync/mutex.rs @@ -352,7 +352,7 @@ pub fn guard_poison<'a, T: ?Sized>(guard: &MutexGuard<'a, T>) -> &'a poison::Fla &guard.__lock.poison } -#[cfg(test)] +#[cfg(all(test, not(target_os = "emscripten")))] mod tests { use sync::mpsc::channel; use sync::{Arc, Mutex, Condvar}; diff --git a/src/libstd/sync/once.rs b/src/libstd/sync/once.rs index 86d2986959..71e163321a 100644 --- a/src/libstd/sync/once.rs +++ b/src/libstd/sync/once.rs @@ -367,7 +367,7 @@ impl OnceState { } } -#[cfg(test)] +#[cfg(all(test, not(target_os = "emscripten")))] mod tests { use panic; use sync::mpsc::channel; @@ -387,7 +387,7 @@ mod tests { #[test] fn stampede_once() { static O: Once = Once::new(); - static mut run: bool = false; + static mut RUN: bool = false; let (tx, rx) = channel(); for _ in 0..10 { @@ -396,10 +396,10 @@ mod tests { for _ in 0..4 { thread::yield_now() } unsafe { O.call_once(|| { - assert!(!run); - run = true; + assert!(!RUN); + RUN = true; }); - assert!(run); + assert!(RUN); } tx.send(()).unwrap(); }); @@ -407,10 +407,10 @@ mod tests { unsafe { O.call_once(|| { - assert!(!run); - run = true; + assert!(!RUN); + RUN = true; }); - assert!(run); + assert!(RUN); } for _ in 0..10 { diff --git a/src/libstd/sync/rwlock.rs b/src/libstd/sync/rwlock.rs index 7f053c6704..f08b764152 100644 --- a/src/libstd/sync/rwlock.rs +++ b/src/libstd/sync/rwlock.rs @@ -136,6 +136,10 @@ impl RwLock { /// This function will return an error if the RwLock is poisoned. An RwLock /// is poisoned whenever a writer panics while holding an exclusive lock. /// The failure will occur immediately after the lock has been acquired. + /// + /// # Panics + /// + /// This function might panic when called if the lock is already held by the current thread. #[inline] #[stable(feature = "rust1", since = "1.0.0")] pub fn read(&self) -> LockResult> { @@ -188,6 +192,10 @@ impl RwLock { /// This function will return an error if the RwLock is poisoned. An RwLock /// is poisoned whenever a writer panics while holding an exclusive lock. /// An error will be returned when the lock is acquired. + /// + /// # Panics + /// + /// This function might panic when called if the lock is already held by the current thread. #[inline] #[stable(feature = "rust1", since = "1.0.0")] pub fn write(&self) -> LockResult> { @@ -380,7 +388,7 @@ impl<'a, T: ?Sized> Drop for RwLockWriteGuard<'a, T> { } } -#[cfg(test)] +#[cfg(all(test, not(target_os = "emscripten")))] mod tests { #![allow(deprecated)] // rand diff --git a/src/libstd/sys/common/args.rs b/src/libstd/sys/common/args.rs deleted file mode 100644 index b5330463e3..0000000000 --- a/src/libstd/sys/common/args.rs +++ /dev/null @@ -1,100 +0,0 @@ -// 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. - -//! Global storage for command line arguments -//! -//! The current incarnation of the Rust runtime expects for -//! the processes `argc` and `argv` arguments to be stored -//! in a globally-accessible location for use by the `os` module. -//! -//! Only valid to call on Linux. Mac and Windows use syscalls to -//! discover the command line arguments. -//! -//! FIXME #7756: Would be nice for this to not exist. - -#![allow(dead_code)] // different code on OSX/linux/etc - -/// One-time global initialization. -pub unsafe fn init(argc: isize, argv: *const *const u8) { imp::init(argc, argv) } - -/// One-time global cleanup. -pub unsafe fn cleanup() { imp::cleanup() } - -/// Make a clone of the global arguments. -pub fn clone() -> Option>> { imp::clone() } - -#[cfg(any(target_os = "linux", - target_os = "android", - target_os = "freebsd", - target_os = "dragonfly", - target_os = "bitrig", - target_os = "netbsd", - target_os = "openbsd", - target_os = "solaris", - target_os = "emscripten", - target_os = "haiku"))] -mod imp { - use libc::c_char; - use mem; - use ffi::CStr; - - use sys_common::mutex::Mutex; - - static mut GLOBAL_ARGS_PTR: usize = 0; - static LOCK: Mutex = Mutex::new(); - - pub unsafe fn init(argc: isize, argv: *const *const u8) { - let args = (0..argc).map(|i| { - CStr::from_ptr(*argv.offset(i) as *const c_char).to_bytes().to_vec() - }).collect(); - - LOCK.lock(); - let ptr = get_global_ptr(); - assert!((*ptr).is_none()); - (*ptr) = Some(box args); - LOCK.unlock(); - } - - pub unsafe fn cleanup() { - LOCK.lock(); - *get_global_ptr() = None; - LOCK.unlock(); - } - - pub fn clone() -> Option>> { - unsafe { - LOCK.lock(); - let ptr = get_global_ptr(); - let ret = (*ptr).as_ref().map(|s| (**s).clone()); - LOCK.unlock(); - return ret - } - } - - fn get_global_ptr() -> *mut Option>>> { - unsafe { mem::transmute(&GLOBAL_ARGS_PTR) } - } - -} - -#[cfg(any(target_os = "macos", - target_os = "ios", - target_os = "windows"))] -mod imp { - pub unsafe fn init(_argc: isize, _argv: *const *const u8) { - } - - pub fn cleanup() { - } - - pub fn clone() -> Option>> { - panic!() - } -} diff --git a/src/libstd/sys/mod.rs b/src/libstd/sys/mod.rs new file mode 100644 index 0000000000..84f41a1c53 --- /dev/null +++ b/src/libstd/sys/mod.rs @@ -0,0 +1,41 @@ +// Copyright 2016 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +//! Platform-dependent platform abstraction +//! +//! The `std::sys` module is the abstracted interface through which +//! `std` talks to the underlying operating system. It has different +//! implementations for different operating system families, today +//! just Unix and Windows. +//! +//! The centralization of platform-specific code in this module is +//! enforced by the "platform abstraction layer" tidy script in +//! `tools/tidy/pal.rs`. +//! +//! This module is closely related to the platform-independent system +//! integration code in `std::sys_common`. See that module's +//! documentation for details. +//! +//! In the future it would be desirable for the indepedent +//! implementations of this module to be extracted to their own crates +//! that `std` can link to, thus enabling their implementation +//! out-of-tree via crate replacement. Though due to the complex +//! inter-dependencies within `std` that will be a challenging goal to +//! achieve. + +pub use self::imp::*; + +#[cfg(unix)] +#[path = "unix/mod.rs"] +mod imp; + +#[cfg(windows)] +#[path = "windows/mod.rs"] +mod imp; diff --git a/src/libstd/sys/unix/android.rs b/src/libstd/sys/unix/android.rs index abbe3fc184..10436723a8 100644 --- a/src/libstd/sys/unix/android.rs +++ b/src/libstd/sys/unix/android.rs @@ -28,10 +28,11 @@ #![cfg(target_os = "android")] -use libc::{c_int, sighandler_t}; +use libc::{c_int, c_void, sighandler_t, size_t, ssize_t}; +use libc::{ftruncate, pread, pwrite}; use io; -use sys::cvt_r; +use super::{cvt, cvt_r}; // The `log2` and `log2f` functions apparently appeared in android-18, or at // least you can see they're not present in the android-17 header [1] and they @@ -96,13 +97,10 @@ pub unsafe fn signal(signum: c_int, handler: sighandler_t) -> sighandler_t { // // If it doesn't we just fall back to `ftruncate`, generating an error for // too-large values. +#[cfg(target_pointer_width = "32")] pub fn ftruncate64(fd: c_int, size: u64) -> io::Result<()> { weak!(fn ftruncate64(c_int, i64) -> c_int); - extern { - fn ftruncate(fd: c_int, off: i32) -> c_int; - } - unsafe { match ftruncate64.get() { Some(f) => cvt_r(|| f(fd, size as i64)).map(|_| ()), @@ -117,3 +115,56 @@ pub fn ftruncate64(fd: c_int, size: u64) -> io::Result<()> { } } } + +#[cfg(target_pointer_width = "64")] +pub fn ftruncate64(fd: c_int, size: u64) -> io::Result<()> { + unsafe { + cvt_r(|| ftruncate(fd, size as i64)).map(|_| ()) + } +} + +#[cfg(target_pointer_width = "32")] +pub unsafe fn cvt_pread64(fd: c_int, buf: *mut c_void, count: size_t, offset: i64) + -> io::Result +{ + use convert::TryInto; + weak!(fn pread64(c_int, *mut c_void, size_t, i64) -> ssize_t); + pread64.get().map(|f| cvt(f(fd, buf, count, offset))).unwrap_or_else(|| { + if let Ok(o) = offset.try_into() { + cvt(pread(fd, buf, count, o)) + } else { + Err(io::Error::new(io::ErrorKind::InvalidInput, + "cannot pread >2GB")) + } + }) +} + +#[cfg(target_pointer_width = "32")] +pub unsafe fn cvt_pwrite64(fd: c_int, buf: *const c_void, count: size_t, offset: i64) + -> io::Result +{ + use convert::TryInto; + weak!(fn pwrite64(c_int, *const c_void, size_t, i64) -> ssize_t); + pwrite64.get().map(|f| cvt(f(fd, buf, count, offset))).unwrap_or_else(|| { + if let Ok(o) = offset.try_into() { + cvt(pwrite(fd, buf, count, o)) + } else { + Err(io::Error::new(io::ErrorKind::InvalidInput, + "cannot pwrite >2GB")) + } + }) +} + +#[cfg(target_pointer_width = "64")] +pub unsafe fn cvt_pread64(fd: c_int, buf: *mut c_void, count: size_t, offset: i64) + -> io::Result +{ + cvt(pread(fd, buf, count, offset)) +} + +#[cfg(target_pointer_width = "64")] +pub unsafe fn cvt_pwrite64(fd: c_int, buf: *const c_void, count: size_t, offset: i64) + -> io::Result +{ + cvt(pwrite(fd, buf, count, offset)) +} diff --git a/src/libstd/sys/unix/args.rs b/src/libstd/sys/unix/args.rs new file mode 100644 index 0000000000..c04fd86367 --- /dev/null +++ b/src/libstd/sys/unix/args.rs @@ -0,0 +1,212 @@ +// 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. + +//! Global initialization and retreival of command line arguments. +//! +//! On some platforms these are stored during runtime startup, +//! and on some they are retrieved from the system on demand. + +#![allow(dead_code)] // runtime init functions not used during testing + +use ffi::OsString; +use marker::PhantomData; +use vec; + +/// One-time global initialization. +pub unsafe fn init(argc: isize, argv: *const *const u8) { imp::init(argc, argv) } + +/// One-time global cleanup. +pub unsafe fn cleanup() { imp::cleanup() } + +/// Returns the command line arguments +pub fn args() -> Args { + imp::args() +} + +pub struct Args { + iter: vec::IntoIter, + _dont_send_or_sync_me: PhantomData<*mut ()>, +} + +impl Iterator for Args { + type Item = OsString; + fn next(&mut self) -> Option { self.iter.next() } + fn size_hint(&self) -> (usize, Option) { self.iter.size_hint() } +} + +impl ExactSizeIterator for Args { + fn len(&self) -> usize { self.iter.len() } +} + +impl DoubleEndedIterator for Args { + fn next_back(&mut self) -> Option { self.iter.next_back() } +} + +#[cfg(any(target_os = "linux", + target_os = "android", + target_os = "freebsd", + target_os = "dragonfly", + target_os = "bitrig", + target_os = "netbsd", + target_os = "openbsd", + target_os = "solaris", + target_os = "emscripten", + target_os = "haiku", + target_os = "fuchsia"))] +mod imp { + use os::unix::prelude::*; + use mem; + use ffi::{CStr, OsString}; + use marker::PhantomData; + use libc; + use super::Args; + + use sys_common::mutex::Mutex; + + static mut GLOBAL_ARGS_PTR: usize = 0; + static LOCK: Mutex = Mutex::new(); + + pub unsafe fn init(argc: isize, argv: *const *const u8) { + let args = (0..argc).map(|i| { + CStr::from_ptr(*argv.offset(i) as *const libc::c_char).to_bytes().to_vec() + }).collect(); + + LOCK.lock(); + let ptr = get_global_ptr(); + assert!((*ptr).is_none()); + (*ptr) = Some(box args); + LOCK.unlock(); + } + + pub unsafe fn cleanup() { + LOCK.lock(); + *get_global_ptr() = None; + LOCK.unlock(); + } + + pub fn args() -> Args { + let bytes = clone().unwrap_or(Vec::new()); + let v: Vec = bytes.into_iter().map(|v| { + OsStringExt::from_vec(v) + }).collect(); + Args { iter: v.into_iter(), _dont_send_or_sync_me: PhantomData } + } + + fn clone() -> Option>> { + unsafe { + LOCK.lock(); + let ptr = get_global_ptr(); + let ret = (*ptr).as_ref().map(|s| (**s).clone()); + LOCK.unlock(); + return ret + } + } + + fn get_global_ptr() -> *mut Option>>> { + unsafe { mem::transmute(&GLOBAL_ARGS_PTR) } + } + +} + +#[cfg(any(target_os = "macos", + target_os = "ios"))] +mod imp { + use ffi::CStr; + use marker::PhantomData; + use libc; + use super::Args; + + pub unsafe fn init(_argc: isize, _argv: *const *const u8) { + } + + pub fn cleanup() { + } + + #[cfg(target_os = "macos")] + pub fn args() -> Args { + use os::unix::prelude::*; + extern { + // These functions are in crt_externs.h. + fn _NSGetArgc() -> *mut libc::c_int; + fn _NSGetArgv() -> *mut *mut *mut libc::c_char; + } + + let vec = unsafe { + let (argc, argv) = (*_NSGetArgc() as isize, + *_NSGetArgv() as *const *const libc::c_char); + (0.. argc as isize).map(|i| { + let bytes = CStr::from_ptr(*argv.offset(i)).to_bytes().to_vec(); + OsStringExt::from_vec(bytes) + }).collect::>() + }; + Args { + iter: vec.into_iter(), + _dont_send_or_sync_me: PhantomData, + } + } + + // As _NSGetArgc and _NSGetArgv aren't mentioned in iOS docs + // and use underscores in their names - they're most probably + // are considered private and therefore should be avoided + // Here is another way to get arguments using Objective C + // runtime + // + // In general it looks like: + // res = Vec::new() + // let args = [[NSProcessInfo processInfo] arguments] + // for i in (0..[args count]) + // res.push([args objectAtIndex:i]) + // res + #[cfg(target_os = "ios")] + pub fn args() -> Args { + use ffi::OsString; + use mem; + use str; + + extern { + fn sel_registerName(name: *const libc::c_uchar) -> Sel; + fn objc_msgSend(obj: NsId, sel: Sel, ...) -> NsId; + fn objc_getClass(class_name: *const libc::c_uchar) -> NsId; + } + + #[link(name = "Foundation", kind = "framework")] + #[link(name = "objc")] + #[cfg(not(cargobuild))] + extern {} + + type Sel = *const libc::c_void; + type NsId = *const libc::c_void; + + let mut res = Vec::new(); + + unsafe { + let process_info_sel = sel_registerName("processInfo\0".as_ptr()); + let arguments_sel = sel_registerName("arguments\0".as_ptr()); + let utf8_sel = sel_registerName("UTF8String\0".as_ptr()); + let count_sel = sel_registerName("count\0".as_ptr()); + let object_at_sel = sel_registerName("objectAtIndex:\0".as_ptr()); + + let klass = objc_getClass("NSProcessInfo\0".as_ptr()); + let info = objc_msgSend(klass, process_info_sel); + let args = objc_msgSend(info, arguments_sel); + + let cnt: usize = mem::transmute(objc_msgSend(args, count_sel)); + for i in 0..cnt { + let tmp = objc_msgSend(args, object_at_sel, i); + let utf_c_str: *const libc::c_char = + mem::transmute(objc_msgSend(tmp, utf8_sel)); + let bytes = CStr::from_ptr(utf_c_str).to_bytes(); + res.push(OsString::from(str::from_utf8(bytes).unwrap())) + } + } + + Args { iter: res.into_iter(), _dont_send_or_sync_me: PhantomData } + } +} diff --git a/src/libstd/sys/unix/env.rs b/src/libstd/sys/unix/env.rs new file mode 100644 index 0000000000..eff3a8c2a3 --- /dev/null +++ b/src/libstd/sys/unix/env.rs @@ -0,0 +1,184 @@ +// 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. + +#[cfg(target_os = "linux")] +pub mod os { + pub const FAMILY: &'static str = "unix"; + pub const OS: &'static str = "linux"; + pub const DLL_PREFIX: &'static str = "lib"; + pub const DLL_SUFFIX: &'static str = ".so"; + pub const DLL_EXTENSION: &'static str = "so"; + pub const EXE_SUFFIX: &'static str = ""; + pub const EXE_EXTENSION: &'static str = ""; +} + +#[cfg(target_os = "macos")] +pub mod os { + pub const FAMILY: &'static str = "unix"; + pub const OS: &'static str = "macos"; + pub const DLL_PREFIX: &'static str = "lib"; + pub const DLL_SUFFIX: &'static str = ".dylib"; + pub const DLL_EXTENSION: &'static str = "dylib"; + pub const EXE_SUFFIX: &'static str = ""; + pub const EXE_EXTENSION: &'static str = ""; +} + +#[cfg(target_os = "ios")] +pub mod os { + pub const FAMILY: &'static str = "unix"; + pub const OS: &'static str = "ios"; + pub const DLL_PREFIX: &'static str = "lib"; + pub const DLL_SUFFIX: &'static str = ".dylib"; + pub const DLL_EXTENSION: &'static str = "dylib"; + pub const EXE_SUFFIX: &'static str = ""; + pub const EXE_EXTENSION: &'static str = ""; +} + +#[cfg(target_os = "freebsd")] +pub mod os { + pub const FAMILY: &'static str = "unix"; + pub const OS: &'static str = "freebsd"; + pub const DLL_PREFIX: &'static str = "lib"; + pub const DLL_SUFFIX: &'static str = ".so"; + pub const DLL_EXTENSION: &'static str = "so"; + pub const EXE_SUFFIX: &'static str = ""; + pub const EXE_EXTENSION: &'static str = ""; +} + +#[cfg(target_os = "dragonfly")] +pub mod os { + pub const FAMILY: &'static str = "unix"; + pub const OS: &'static str = "dragonfly"; + pub const DLL_PREFIX: &'static str = "lib"; + pub const DLL_SUFFIX: &'static str = ".so"; + pub const DLL_EXTENSION: &'static str = "so"; + pub const EXE_SUFFIX: &'static str = ""; + pub const EXE_EXTENSION: &'static str = ""; +} + +#[cfg(target_os = "bitrig")] +pub mod os { + pub const FAMILY: &'static str = "unix"; + pub const OS: &'static str = "bitrig"; + pub const DLL_PREFIX: &'static str = "lib"; + pub const DLL_SUFFIX: &'static str = ".so"; + pub const DLL_EXTENSION: &'static str = "so"; + pub const EXE_SUFFIX: &'static str = ""; + pub const EXE_EXTENSION: &'static str = ""; +} + +#[cfg(target_os = "netbsd")] +pub mod os { + pub const FAMILY: &'static str = "unix"; + pub const OS: &'static str = "netbsd"; + pub const DLL_PREFIX: &'static str = "lib"; + pub const DLL_SUFFIX: &'static str = ".so"; + pub const DLL_EXTENSION: &'static str = "so"; + pub const EXE_SUFFIX: &'static str = ""; + pub const EXE_EXTENSION: &'static str = ""; +} + +#[cfg(target_os = "openbsd")] +pub mod os { + pub const FAMILY: &'static str = "unix"; + pub const OS: &'static str = "openbsd"; + pub const DLL_PREFIX: &'static str = "lib"; + pub const DLL_SUFFIX: &'static str = ".so"; + pub const DLL_EXTENSION: &'static str = "so"; + pub const EXE_SUFFIX: &'static str = ""; + pub const EXE_EXTENSION: &'static str = ""; +} + +#[cfg(target_os = "android")] +pub mod os { + pub const FAMILY: &'static str = "unix"; + pub const OS: &'static str = "android"; + pub const DLL_PREFIX: &'static str = "lib"; + pub const DLL_SUFFIX: &'static str = ".so"; + pub const DLL_EXTENSION: &'static str = "so"; + pub const EXE_SUFFIX: &'static str = ""; + pub const EXE_EXTENSION: &'static str = ""; +} + +#[cfg(target_os = "solaris")] +pub mod os { + pub const FAMILY: &'static str = "unix"; + pub const OS: &'static str = "solaris"; + pub const DLL_PREFIX: &'static str = "lib"; + pub const DLL_SUFFIX: &'static str = ".so"; + pub const DLL_EXTENSION: &'static str = "so"; + pub const EXE_SUFFIX: &'static str = ""; + pub const EXE_EXTENSION: &'static str = ""; +} + +#[cfg(all(target_os = "nacl", not(target_arch = "le32")))] +pub mod os { + pub const FAMILY: &'static str = "unix"; + pub const OS: &'static str = "nacl"; + pub const DLL_PREFIX: &'static str = "lib"; + pub const DLL_SUFFIX: &'static str = ".so"; + pub const DLL_EXTENSION: &'static str = "so"; + pub const EXE_SUFFIX: &'static str = ".nexe"; + pub const EXE_EXTENSION: &'static str = "nexe"; +} +#[cfg(all(target_os = "nacl", target_arch = "le32"))] +pub mod os { + pub const FAMILY: &'static str = "unix"; + pub const OS: &'static str = "pnacl"; + pub const DLL_PREFIX: &'static str = "lib"; + pub const DLL_SUFFIX: &'static str = ".pso"; + pub const DLL_EXTENSION: &'static str = "pso"; + pub const EXE_SUFFIX: &'static str = ".pexe"; + pub const EXE_EXTENSION: &'static str = "pexe"; +} + +#[cfg(target_os = "haiku")] +pub mod os { + pub const FAMILY: &'static str = "unix"; + pub const OS: &'static str = "haiku"; + pub const DLL_PREFIX: &'static str = "lib"; + pub const DLL_SUFFIX: &'static str = ".so"; + pub const DLL_EXTENSION: &'static str = "so"; + pub const EXE_SUFFIX: &'static str = ""; + pub const EXE_EXTENSION: &'static str = ""; +} + +#[cfg(all(target_os = "emscripten", target_arch = "asmjs"))] +pub mod os { + pub const FAMILY: &'static str = "unix"; + pub const OS: &'static str = "emscripten"; + pub const DLL_PREFIX: &'static str = "lib"; + pub const DLL_SUFFIX: &'static str = ".so"; + pub const DLL_EXTENSION: &'static str = "so"; + pub const EXE_SUFFIX: &'static str = ".js"; + pub const EXE_EXTENSION: &'static str = "js"; +} + +#[cfg(all(target_os = "emscripten", target_arch = "wasm32"))] +pub mod os { + pub const FAMILY: &'static str = "unix"; + pub const OS: &'static str = "emscripten"; + pub const DLL_PREFIX: &'static str = "lib"; + pub const DLL_SUFFIX: &'static str = ".so"; + pub const DLL_EXTENSION: &'static str = "so"; + pub const EXE_SUFFIX: &'static str = ".js"; + pub const EXE_EXTENSION: &'static str = "js"; +} + +#[cfg(target_os = "fuchsia")] +pub mod os { + pub const FAMILY: &'static str = "unix"; + pub const OS: &'static str = "fuchsia"; + pub const DLL_PREFIX: &'static str = "lib"; + pub const DLL_SUFFIX: &'static str = ".so"; + pub const DLL_EXTENSION: &'static str = "so"; + pub const EXE_SUFFIX: &'static str = ""; + pub const EXE_EXTENSION: &'static str = ""; +} diff --git a/src/libstd/sys/unix/ext/fs.rs b/src/libstd/sys/unix/ext/fs.rs index 77587918ac..fcfab05158 100644 --- a/src/libstd/sys/unix/ext/fs.rs +++ b/src/libstd/sys/unix/ext/fs.rs @@ -20,6 +20,51 @@ use sys; use sys_common::{FromInner, AsInner, AsInnerMut}; use sys::platform::fs::MetadataExt as UnixMetadataExt; +/// Unix-specific extensions to `File` +#[unstable(feature = "file_offset", issue = "35918")] +pub trait FileExt { + /// Reads a number of bytes starting from a given offset. + /// + /// Returns the number of bytes read. + /// + /// The offset is relative to the start of the file and thus independent + /// from the current cursor. + /// + /// The current file cursor is not affected by this function. + /// + /// Note that similar to `File::read`, it is not an error to return with a + /// short read. + #[unstable(feature = "file_offset", issue = "35918")] + fn read_at(&self, buf: &mut [u8], offset: u64) -> io::Result; + + /// Writes a number of bytes starting from a given offset. + /// + /// Returns the number of bytes written. + /// + /// The offset is relative to the start of the file and thus independent + /// from the current cursor. + /// + /// The current file cursor is not affected by this function. + /// + /// When writing beyond the end of the file, the file is appropiately + /// extended and the intermediate bytes are initialized with the value 0. + /// + /// Note that similar to `File::write`, it is not an error to return a + /// short write. + #[unstable(feature = "file_offset", issue = "35918")] + fn write_at(&self, buf: &[u8], offset: u64) -> io::Result; +} + +#[unstable(feature = "file_offset", issue = "35918")] +impl FileExt for fs::File { + fn read_at(&self, buf: &mut [u8], offset: u64) -> io::Result { + self.as_inner().read_at(buf, offset) + } + fn write_at(&self, buf: &[u8], offset: u64) -> io::Result { + self.as_inner().write_at(buf, offset) + } +} + /// Unix-specific extensions to `Permissions` #[stable(feature = "fs_ext", since = "1.1.0")] pub trait PermissionsExt { diff --git a/src/libstd/sys/unix/ext/mod.rs b/src/libstd/sys/unix/ext/mod.rs index 1be3d75d86..b2483f4e20 100644 --- a/src/libstd/sys/unix/ext/mod.rs +++ b/src/libstd/sys/unix/ext/mod.rs @@ -50,6 +50,8 @@ pub mod prelude { pub use super::fs::{PermissionsExt, OpenOptionsExt, MetadataExt, FileTypeExt}; #[doc(no_inline)] #[stable(feature = "rust1", since = "1.0.0")] pub use super::fs::DirEntryExt; + #[doc(no_inline)] #[unstable(feature = "file_offset", issue = "35918")] + pub use super::fs::FileExt; #[doc(no_inline)] #[stable(feature = "rust1", since = "1.0.0")] pub use super::thread::JoinHandleExt; #[doc(no_inline)] #[stable(feature = "rust1", since = "1.0.0")] diff --git a/src/libstd/sys/unix/ext/net.rs b/src/libstd/sys/unix/ext/net.rs index 3f93fce193..80f53da1ce 100644 --- a/src/libstd/sys/unix/ext/net.rs +++ b/src/libstd/sys/unix/ext/net.rs @@ -28,6 +28,17 @@ use sys::cvt; use sys::net::Socket; use sys_common::{AsInner, FromInner, IntoInner}; +#[cfg(any(target_os = "linux", target_os = "android", + target_os = "dragonfly", target_os = "freebsd", + target_os = "openbsd", target_os = "netbsd", + target_os = "haiku", target_os = "bitrig"))] +use libc::MSG_NOSIGNAL; +#[cfg(not(any(target_os = "linux", target_os = "android", + target_os = "dragonfly", target_os = "freebsd", + target_os = "openbsd", target_os = "netbsd", + target_os = "haiku", target_os = "bitrig")))] +const MSG_NOSIGNAL: libc::c_int = 0x0; + fn sun_path_offset() -> usize { unsafe { // Work with an actual instance of the type since using a null pointer is UB @@ -690,7 +701,7 @@ impl UnixDatagram { let count = cvt(libc::sendto(*d.0.as_inner(), buf.as_ptr() as *const _, buf.len(), - 0, + MSG_NOSIGNAL, &addr as *const _ as *const _, len))?; Ok(count as usize) @@ -786,7 +797,7 @@ impl IntoRawFd for UnixDatagram { } } -#[cfg(test)] +#[cfg(all(test, not(target_os = "emscripten")))] mod test { use thread; use io; diff --git a/src/libstd/sys/unix/ext/process.rs b/src/libstd/sys/unix/ext/process.rs index 5bd92f2eb5..3a7c59d4e6 100644 --- a/src/libstd/sys/unix/ext/process.rs +++ b/src/libstd/sys/unix/ext/process.rs @@ -161,21 +161,21 @@ impl AsRawFd for process::ChildStderr { } } -#[stable(feature = "process_extensions", since = "1.2.0")] +#[stable(feature = "into_raw_os", since = "1.4.0")] impl IntoRawFd for process::ChildStdin { fn into_raw_fd(self) -> RawFd { self.into_inner().into_fd().into_raw() } } -#[stable(feature = "process_extensions", since = "1.2.0")] +#[stable(feature = "into_raw_os", since = "1.4.0")] impl IntoRawFd for process::ChildStdout { fn into_raw_fd(self) -> RawFd { self.into_inner().into_fd().into_raw() } } -#[stable(feature = "process_extensions", since = "1.2.0")] +#[stable(feature = "into_raw_os", since = "1.4.0")] impl IntoRawFd for process::ChildStderr { fn into_raw_fd(self) -> RawFd { self.into_inner().into_fd().into_raw() diff --git a/src/libstd/sys/unix/fast_thread_local.rs b/src/libstd/sys/unix/fast_thread_local.rs new file mode 100644 index 0000000000..0c625e7add --- /dev/null +++ b/src/libstd/sys/unix/fast_thread_local.rs @@ -0,0 +1,167 @@ +// 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. + +#![cfg(target_thread_local)] +#![unstable(feature = "thread_local_internals", issue = "0")] + +use cell::{Cell, UnsafeCell}; +use intrinsics; +use ptr; + +pub struct Key { + inner: UnsafeCell>, + + // Metadata to keep track of the state of the destructor. Remember that + // these variables are thread-local, not global. + dtor_registered: Cell, + dtor_running: Cell, +} + +unsafe impl ::marker::Sync for Key { } + +impl Key { + pub const fn new() -> Key { + Key { + inner: UnsafeCell::new(None), + dtor_registered: Cell::new(false), + dtor_running: Cell::new(false) + } + } + + pub fn get(&'static self) -> Option<&'static UnsafeCell>> { + unsafe { + if intrinsics::needs_drop::() && self.dtor_running.get() { + return None + } + self.register_dtor(); + } + Some(&self.inner) + } + + unsafe fn register_dtor(&self) { + if !intrinsics::needs_drop::() || self.dtor_registered.get() { + return + } + + register_dtor(self as *const _ as *mut u8, + destroy_value::); + self.dtor_registered.set(true); + } +} + +#[cfg(any(target_os = "linux", target_os = "fuchsia"))] +unsafe fn register_dtor_fallback(t: *mut u8, dtor: unsafe extern fn(*mut u8)) { + // The fallback implementation uses a vanilla OS-based TLS key to track + // the list of destructors that need to be run for this thread. The key + // then has its own destructor which runs all the other destructors. + // + // The destructor for DTORS is a little special in that it has a `while` + // loop to continuously drain the list of registered destructors. It + // *should* be the case that this loop always terminates because we + // provide the guarantee that a TLS key cannot be set after it is + // flagged for destruction. + use sys_common::thread_local as os; + + static DTORS: os::StaticKey = os::StaticKey::new(Some(run_dtors)); + type List = Vec<(*mut u8, unsafe extern fn(*mut u8))>; + if DTORS.get().is_null() { + let v: Box = box Vec::new(); + DTORS.set(Box::into_raw(v) as *mut u8); + } + let list: &mut List = &mut *(DTORS.get() as *mut List); + list.push((t, dtor)); + + unsafe extern fn run_dtors(mut ptr: *mut u8) { + while !ptr.is_null() { + let list: Box = Box::from_raw(ptr as *mut List); + for &(ptr, dtor) in list.iter() { + dtor(ptr); + } + ptr = DTORS.get(); + DTORS.set(ptr::null_mut()); + } + } +} + +// Since what appears to be glibc 2.18 this symbol has been shipped which +// GCC and clang both use to invoke destructors in thread_local globals, so +// let's do the same! +// +// Note, however, that we run on lots older linuxes, as well as cross +// compiling from a newer linux to an older linux, so we also have a +// fallback implementation to use as well. +// +// Due to rust-lang/rust#18804, make sure this is not generic! +#[cfg(target_os = "linux")] +unsafe fn register_dtor(t: *mut u8, dtor: unsafe extern fn(*mut u8)) { + use mem; + use libc; + + extern { + #[linkage = "extern_weak"] + static __dso_handle: *mut u8; + #[linkage = "extern_weak"] + static __cxa_thread_atexit_impl: *const libc::c_void; + } + if !__cxa_thread_atexit_impl.is_null() { + type F = unsafe extern fn(dtor: unsafe extern fn(*mut u8), + arg: *mut u8, + dso_handle: *mut u8) -> libc::c_int; + mem::transmute::<*const libc::c_void, F>(__cxa_thread_atexit_impl) + (dtor, t, &__dso_handle as *const _ as *mut _); + return + } + register_dtor_fallback(t, dtor); +} + +// OSX's analog of the above linux function is this _tlv_atexit function. +// The disassembly of thread_local globals in C++ (at least produced by +// clang) will have this show up in the output. +#[cfg(target_os = "macos")] +unsafe fn register_dtor(t: *mut u8, dtor: unsafe extern fn(*mut u8)) { + extern { + fn _tlv_atexit(dtor: unsafe extern fn(*mut u8), + arg: *mut u8); + } + _tlv_atexit(dtor, t); +} + +// Just use the thread_local fallback implementation, at least until there's +// a more direct implementation. +#[cfg(target_os = "fuchsia")] +unsafe fn register_dtor(t: *mut u8, dtor: unsafe extern fn(*mut u8)) { + register_dtor_fallback(t, dtor); +} + +pub unsafe extern fn destroy_value(ptr: *mut u8) { + let ptr = ptr as *mut Key; + // Right before we run the user destructor be sure to flag the + // destructor as running for this thread so calls to `get` will return + // `None`. + (*ptr).dtor_running.set(true); + + // The OSX implementation of TLS apparently had an odd aspect to it + // where the pointer we have may be overwritten while this destructor + // is running. Specifically if a TLS destructor re-accesses TLS it may + // trigger a re-initialization of all TLS variables, paving over at + // least some destroyed ones with initial values. + // + // This means that if we drop a TLS value in place on OSX that we could + // revert the value to its original state halfway through the + // destructor, which would be bad! + // + // Hence, we use `ptr::read` on OSX (to move to a "safe" location) + // instead of drop_in_place. + if cfg!(target_os = "macos") { + ptr::read((*ptr).inner.get()); + } else { + ptr::drop_in_place((*ptr).inner.get()); + } +} diff --git a/src/libstd/sys/unix/fd.rs b/src/libstd/sys/unix/fd.rs index 60c1750b46..41bb96fed1 100644 --- a/src/libstd/sys/unix/fd.rs +++ b/src/libstd/sys/unix/fd.rs @@ -11,7 +11,7 @@ #![unstable(reason = "not public", issue = "0", feature = "fd")] use io::{self, Read}; -use libc::{self, c_int, size_t, c_void}; +use libc::{self, c_int, c_void}; use mem; use sync::atomic::{AtomicBool, Ordering}; use sys::cvt; @@ -40,7 +40,7 @@ impl FileDesc { let ret = cvt(unsafe { libc::read(self.fd, buf.as_mut_ptr() as *mut c_void, - buf.len() as size_t) + buf.len()) })?; Ok(ret as usize) } @@ -50,15 +50,63 @@ impl FileDesc { (&mut me).read_to_end(buf) } + pub fn read_at(&self, buf: &mut [u8], offset: u64) -> io::Result { + #[cfg(target_os = "android")] + use super::android::cvt_pread64; + + #[cfg(not(target_os = "android"))] + unsafe fn cvt_pread64(fd: c_int, buf: *mut c_void, count: usize, offset: i64) + -> io::Result + { + #[cfg(any(target_os = "linux", target_os = "emscripten"))] + use libc::pread64; + #[cfg(not(any(target_os = "linux", target_os = "emscripten")))] + use libc::pread as pread64; + cvt(pread64(fd, buf, count, offset)) + } + + unsafe { + cvt_pread64(self.fd, + buf.as_mut_ptr() as *mut c_void, + buf.len(), + offset as i64) + .map(|n| n as usize) + } + } + pub fn write(&self, buf: &[u8]) -> io::Result { let ret = cvt(unsafe { libc::write(self.fd, buf.as_ptr() as *const c_void, - buf.len() as size_t) + buf.len()) })?; Ok(ret as usize) } + pub fn write_at(&self, buf: &[u8], offset: u64) -> io::Result { + #[cfg(target_os = "android")] + use super::android::cvt_pwrite64; + + #[cfg(not(target_os = "android"))] + unsafe fn cvt_pwrite64(fd: c_int, buf: *const c_void, count: usize, offset: i64) + -> io::Result + { + #[cfg(any(target_os = "linux", target_os = "emscripten"))] + use libc::pwrite64; + #[cfg(not(any(target_os = "linux", target_os = "emscripten")))] + use libc::pwrite as pwrite64; + cvt(pwrite64(fd, buf, count, offset)) + } + + unsafe { + cvt_pwrite64(self.fd, + buf.as_ptr() as *const c_void, + buf.len(), + offset as i64) + .map(|n| n as usize) + } + } + #[cfg(not(any(target_env = "newlib", target_os = "solaris", target_os = "emscripten", diff --git a/src/libstd/sys/unix/fs.rs b/src/libstd/sys/unix/fs.rs index d015aeee33..0b43fd2ac8 100644 --- a/src/libstd/sys/unix/fs.rs +++ b/src/libstd/sys/unix/fs.rs @@ -193,6 +193,14 @@ impl FromInner for FilePermissions { } } +impl fmt::Debug for ReadDir { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + // This will only be called from std::fs::ReadDir, which will add a "ReadDir()" frame. + // Thus the result will be e g 'ReadDir("/home")' + fmt::Debug::fmt(&*self.root, f) + } +} + impl Iterator for ReadDir { type Item = io::Result; @@ -304,7 +312,8 @@ impl DirEntry { target_os = "emscripten", target_os = "android", target_os = "solaris", - target_os = "haiku"))] + target_os = "haiku", + target_os = "fuchsia"))] pub fn ino(&self) -> u64 { self.entry.d_ino as u64 } @@ -334,7 +343,8 @@ impl DirEntry { #[cfg(any(target_os = "android", target_os = "linux", target_os = "emscripten", - target_os = "haiku"))] + target_os = "haiku", + target_os = "fuchsia"))] fn name_bytes(&self) -> &[u8] { unsafe { CStr::from_ptr(self.entry.d_name.as_ptr()).to_bytes() @@ -483,10 +493,18 @@ impl File { self.0.read_to_end(buf) } + pub fn read_at(&self, buf: &mut [u8], offset: u64) -> io::Result { + self.0.read_at(buf, offset) + } + pub fn write(&self, buf: &[u8]) -> io::Result { self.0.write(buf) } + pub fn write_at(&self, buf: &[u8], offset: u64) -> io::Result { + self.0.write_at(buf, offset) + } + pub fn flush(&self) -> io::Result<()> { Ok(()) } pub fn seek(&self, pos: SeekFrom) -> io::Result { @@ -669,7 +687,7 @@ pub fn readlink(p: &Path) -> io::Result { loop { let buf_read = cvt(unsafe { - libc::readlink(p, buf.as_mut_ptr() as *mut _, buf.capacity() as libc::size_t) + libc::readlink(p, buf.as_mut_ptr() as *mut _, buf.capacity()) })? as usize; unsafe { buf.set_len(buf_read); } diff --git a/src/libstd/sys/unix/memchr.rs b/src/libstd/sys/unix/memchr.rs new file mode 100644 index 0000000000..aed04703ea --- /dev/null +++ b/src/libstd/sys/unix/memchr.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. +// +// Original implementation taken from rust-memchr +// Copyright 2015 Andrew Gallant, bluss and Nicolas Koch + +pub fn memchr(needle: u8, haystack: &[u8]) -> Option { + use libc; + + let p = unsafe { + libc::memchr( + haystack.as_ptr() as *const libc::c_void, + needle as libc::c_int, + haystack.len()) + }; + if p.is_null() { + None + } else { + Some(p as usize - (haystack.as_ptr() as usize)) + } +} + +pub fn memrchr(needle: u8, haystack: &[u8]) -> Option { + + #[cfg(target_os = "linux")] + fn memrchr_specific(needle: u8, haystack: &[u8]) -> Option { + use libc; + + // GNU's memrchr() will - unlike memchr() - error if haystack is empty. + if haystack.is_empty() {return None} + let p = unsafe { + libc::memrchr( + haystack.as_ptr() as *const libc::c_void, + needle as libc::c_int, + haystack.len()) + }; + if p.is_null() { + None + } else { + Some(p as usize - (haystack.as_ptr() as usize)) + } + } + + #[cfg(not(target_os = "linux"))] + fn memrchr_specific(needle: u8, haystack: &[u8]) -> Option { + ::sys_common::memchr::fallback::memrchr(needle, haystack) + } + + memrchr_specific(needle, haystack) +} diff --git a/src/libstd/sys/unix/mod.rs b/src/libstd/sys/unix/mod.rs index 3fbeda58e8..fd7dc17ccc 100644 --- a/src/libstd/sys/unix/mod.rs +++ b/src/libstd/sys/unix/mod.rs @@ -26,21 +26,27 @@ use libc; #[cfg(target_os = "openbsd")] pub use os::openbsd as platform; #[cfg(target_os = "solaris")] pub use os::solaris as platform; #[cfg(target_os = "emscripten")] pub use os::emscripten as platform; +#[cfg(target_os = "fuchsia")] pub use os::fuchsia as platform; #[macro_use] pub mod weak; +pub mod args; pub mod android; #[cfg(any(not(cargobuild), feature = "backtrace"))] pub mod backtrace; pub mod condvar; +pub mod env; pub mod ext; +pub mod fast_thread_local; pub mod fd; pub mod fs; +pub mod memchr; pub mod mutex; pub mod net; pub mod os; pub mod os_str; +pub mod path; pub mod pipe; pub mod process; pub mod rand; @@ -79,16 +85,16 @@ pub fn init() { unsafe { libc::write(libc::STDERR_FILENO, msg.as_ptr() as *const libc::c_void, - msg.len() as libc::size_t); + msg.len()); intrinsics::abort(); } } - #[cfg(not(any(target_os = "nacl", target_os = "emscripten")))] + #[cfg(not(any(target_os = "nacl", target_os = "emscripten", target_os="fuchsia")))] unsafe fn reset_sigpipe() { assert!(signal(libc::SIGPIPE, libc::SIG_IGN) != !0); } - #[cfg(any(target_os = "nacl", target_os = "emscripten"))] + #[cfg(any(target_os = "nacl", target_os = "emscripten", target_os="fuchsia"))] unsafe fn reset_sigpipe() {} } @@ -157,3 +163,14 @@ pub fn cvt_r(mut f: F) -> io::Result } } } + +// On Unix-like platforms, libc::abort will unregister signal handlers +// including the SIGABRT handler, preventing the abort from being blocked, and +// fclose streams, with the side effect of flushing them so libc bufferred +// output will be printed. Additionally the shell will generally print a more +// understandable error message like "Abort trap" rather than "Illegal +// instruction" that intrinsics::abort would cause, as intrinsics::abort is +// implemented as an illegal instruction. +pub unsafe fn abort_internal() -> ! { + ::libc::abort() +} diff --git a/src/libstd/sys/unix/net.rs b/src/libstd/sys/unix/net.rs index ec7ccdf589..ad287bbec3 100644 --- a/src/libstd/sys/unix/net.rs +++ b/src/libstd/sys/unix/net.rs @@ -33,6 +33,14 @@ use libc::SOCK_CLOEXEC; #[cfg(not(target_os = "linux"))] const SOCK_CLOEXEC: c_int = 0; +// Another conditional contant for name resolution: Macos et iOS use +// SO_NOSIGPIPE as a setsockopt flag to disable SIGPIPE emission on socket. +// Other platforms do otherwise. +#[cfg(target_vendor = "apple")] +use libc::SO_NOSIGPIPE; +#[cfg(not(target_vendor = "apple"))] +const SO_NOSIGPIPE: c_int = 0; + pub struct Socket(FileDesc); pub fn init() {} @@ -81,7 +89,11 @@ impl Socket { let fd = cvt(libc::socket(fam, ty, 0))?; let fd = FileDesc::new(fd); fd.set_cloexec()?; - Ok(Socket(fd)) + let socket = Socket(fd); + if cfg!(target_vendor = "apple") { + setsockopt(&socket, libc::SOL_SOCKET, SO_NOSIGPIPE, 1)?; + } + Ok(socket) } } diff --git a/src/libstd/sys/unix/os.rs b/src/libstd/sys/unix/os.rs index 850c3d5271..e591f25cac 100644 --- a/src/libstd/sys/unix/os.rs +++ b/src/libstd/sys/unix/os.rs @@ -38,7 +38,7 @@ static ENV_LOCK: Mutex = Mutex::new(); extern { #[cfg(not(target_os = "dragonfly"))] - #[cfg_attr(any(target_os = "linux", target_os = "emscripten"), + #[cfg_attr(any(target_os = "linux", target_os = "emscripten", target_os = "fuchsia"), link_name = "__errno_location")] #[cfg_attr(any(target_os = "bitrig", target_os = "netbsd", @@ -94,7 +94,7 @@ pub fn error_string(errno: i32) -> String { let p = buf.as_mut_ptr(); unsafe { - if strerror_r(errno as c_int, p, buf.len() as libc::size_t) < 0 { + if strerror_r(errno as c_int, p, buf.len()) < 0 { panic!("strerror_r failure"); } @@ -108,7 +108,7 @@ pub fn getcwd() -> io::Result { loop { unsafe { let ptr = buf.as_mut_ptr() as *mut libc::c_char; - if !libc::getcwd(ptr, buf.capacity() as libc::size_t).is_null() { + if !libc::getcwd(ptr, buf.capacity()).is_null() { let len = CStr::from_ptr(buf.as_ptr() as *const libc::c_char).to_bytes().len(); buf.set_len(len); buf.shrink_to_fit(); @@ -200,21 +200,20 @@ pub fn current_exe() -> io::Result { libc::KERN_PROC as c_int, libc::KERN_PROC_PATHNAME as c_int, -1 as c_int]; - let mut sz: libc::size_t = 0; + let mut sz = 0; cvt(libc::sysctl(mib.as_mut_ptr(), mib.len() as ::libc::c_uint, - ptr::null_mut(), &mut sz, ptr::null_mut(), - 0 as libc::size_t))?; + ptr::null_mut(), &mut sz, ptr::null_mut(), 0))?; if sz == 0 { return Err(io::Error::last_os_error()) } - let mut v: Vec = Vec::with_capacity(sz as usize); + let mut v: Vec = Vec::with_capacity(sz); cvt(libc::sysctl(mib.as_mut_ptr(), mib.len() as ::libc::c_uint, v.as_mut_ptr() as *mut libc::c_void, &mut sz, - ptr::null_mut(), 0 as libc::size_t))?; + ptr::null_mut(), 0))?; if sz == 0 { return Err(io::Error::last_os_error()); } - v.set_len(sz as usize - 1); // chop off trailing NUL + v.set_len(sz - 1); // chop off trailing NUL Ok(PathBuf::from(OsString::from_vec(v))) } } @@ -347,124 +346,10 @@ pub fn current_exe() -> io::Result { } } -pub struct Args { - iter: vec::IntoIter, - _dont_send_or_sync_me: PhantomData<*mut ()>, -} - -impl Iterator for Args { - type Item = OsString; - fn next(&mut self) -> Option { self.iter.next() } - fn size_hint(&self) -> (usize, Option) { self.iter.size_hint() } -} - -impl ExactSizeIterator for Args { - fn len(&self) -> usize { self.iter.len() } -} - -impl DoubleEndedIterator for Args { - fn next_back(&mut self) -> Option { self.iter.next_back() } -} - -/// Returns the command line arguments -/// -/// Returns a list of the command line arguments. -#[cfg(target_os = "macos")] -pub fn args() -> Args { - extern { - // These functions are in crt_externs.h. - fn _NSGetArgc() -> *mut c_int; - fn _NSGetArgv() -> *mut *mut *mut c_char; - } - - let vec = unsafe { - let (argc, argv) = (*_NSGetArgc() as isize, - *_NSGetArgv() as *const *const c_char); - (0.. argc as isize).map(|i| { - let bytes = CStr::from_ptr(*argv.offset(i)).to_bytes().to_vec(); - OsStringExt::from_vec(bytes) - }).collect::>() - }; - Args { - iter: vec.into_iter(), - _dont_send_or_sync_me: PhantomData, - } -} - -// As _NSGetArgc and _NSGetArgv aren't mentioned in iOS docs -// and use underscores in their names - they're most probably -// are considered private and therefore should be avoided -// Here is another way to get arguments using Objective C -// runtime -// -// In general it looks like: -// res = Vec::new() -// let args = [[NSProcessInfo processInfo] arguments] -// for i in (0..[args count]) -// res.push([args objectAtIndex:i]) -// res -#[cfg(target_os = "ios")] -pub fn args() -> Args { - use mem; - - extern { - fn sel_registerName(name: *const libc::c_uchar) -> Sel; - fn objc_msgSend(obj: NsId, sel: Sel, ...) -> NsId; - fn objc_getClass(class_name: *const libc::c_uchar) -> NsId; - } - - #[link(name = "Foundation", kind = "framework")] - #[link(name = "objc")] - #[cfg(not(cargobuild))] - extern {} - - type Sel = *const libc::c_void; - type NsId = *const libc::c_void; - - let mut res = Vec::new(); - - unsafe { - let process_info_sel = sel_registerName("processInfo\0".as_ptr()); - let arguments_sel = sel_registerName("arguments\0".as_ptr()); - let utf8_sel = sel_registerName("UTF8String\0".as_ptr()); - let count_sel = sel_registerName("count\0".as_ptr()); - let object_at_sel = sel_registerName("objectAtIndex:\0".as_ptr()); - - let klass = objc_getClass("NSProcessInfo\0".as_ptr()); - let info = objc_msgSend(klass, process_info_sel); - let args = objc_msgSend(info, arguments_sel); - - let cnt: usize = mem::transmute(objc_msgSend(args, count_sel)); - for i in 0..cnt { - let tmp = objc_msgSend(args, object_at_sel, i); - let utf_c_str: *const libc::c_char = - mem::transmute(objc_msgSend(tmp, utf8_sel)); - let bytes = CStr::from_ptr(utf_c_str).to_bytes(); - res.push(OsString::from(str::from_utf8(bytes).unwrap())) - } - } - - Args { iter: res.into_iter(), _dont_send_or_sync_me: PhantomData } -} - -#[cfg(any(target_os = "linux", - target_os = "android", - target_os = "freebsd", - target_os = "dragonfly", - target_os = "bitrig", - target_os = "netbsd", - target_os = "openbsd", - target_os = "solaris", - target_os = "nacl", - target_os = "emscripten", - target_os = "haiku"))] -pub fn args() -> Args { - use sys_common; - let bytes = sys_common::args::clone().unwrap_or(Vec::new()); - let v: Vec = bytes.into_iter().map(|v| { - OsStringExt::from_vec(v) - }).collect(); - Args { iter: v.into_iter(), _dont_send_or_sync_me: PhantomData } +#[cfg(target_os = "fuchsia")] +pub fn current_exe() -> io::Result { + use io::ErrorKind; + Err(io::Error::new(ErrorKind::Other, "Not yet implemented on fuchsia")) } pub struct Env { @@ -608,7 +493,7 @@ pub fn home_dir() -> Option { buf: &mut Vec) -> Option<()> { let mut result = ptr::null_mut(); match libc::getpwuid_r(me, passwd, buf.as_mut_ptr(), - buf.capacity() as libc::size_t, + buf.capacity(), &mut result) { 0 if !result.is_null() => Some(()), _ => None @@ -621,7 +506,7 @@ pub fn home_dir() -> Option { // getpwuid_r semantics is different on Illumos/Solaris: // http://illumos.org/man/3c/getpwuid_r let result = libc::getpwuid_r(me, passwd, buf.as_mut_ptr(), - buf.capacity() as libc::size_t); + buf.capacity()); if result.is_null() { None } else { Some(()) } } diff --git a/src/libstd/sys/unix/path.rs b/src/libstd/sys/unix/path.rs new file mode 100644 index 0000000000..bf9af7a435 --- /dev/null +++ b/src/libstd/sys/unix/path.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. + +use path::Prefix; +use ffi::OsStr; + +#[inline] +pub fn is_sep_byte(b: u8) -> bool { + b == b'/' +} + +#[inline] +pub fn is_verbatim_sep(b: u8) -> bool { + b == b'/' +} + +pub fn parse_prefix(_: &OsStr) -> Option { + None +} + +pub const MAIN_SEP_STR: &'static str = "/"; +pub const MAIN_SEP: char = '/'; diff --git a/src/libstd/sys/unix/process.rs b/src/libstd/sys/unix/process.rs index 50014f51f6..dafc11d9cc 100644 --- a/src/libstd/sys/unix/process.rs +++ b/src/libstd/sys/unix/process.rs @@ -369,7 +369,7 @@ impl Command { } // NaCl has no signal support. - if cfg!(not(target_os = "nacl")) { + if cfg!(not(any(target_os = "nacl", target_os = "emscripten"))) { // Reset signal handling so the child process starts in a // standardized state. libstd ignores SIGPIPE, and signal-handling // libraries often set a mask. Child processes inherit ignored @@ -589,7 +589,7 @@ impl Process { } } -#[cfg(test)] +#[cfg(all(test, not(target_os = "emscripten")))] mod tests { use super::*; diff --git a/src/libstd/sys/unix/rand.rs b/src/libstd/sys/unix/rand.rs index 6b50ca9bcd..9b1cf6ffd0 100644 --- a/src/libstd/sys/unix/rand.rs +++ b/src/libstd/sys/unix/rand.rs @@ -27,7 +27,8 @@ fn next_u64(mut fill_buf: &mut FnMut(&mut [u8])) -> u64 { #[cfg(all(unix, not(target_os = "ios"), not(target_os = "openbsd"), - not(target_os = "freebsd")))] + not(target_os = "freebsd"), + not(target_os = "fuchsia")))] mod imp { use self::OsRngInner::*; use super::{next_u32, next_u64}; @@ -97,8 +98,8 @@ mod imp { // full entropy pool let reader = File::open("/dev/urandom").expect("Unable to open /dev/urandom"); let mut reader_rng = ReaderRng::new(reader); - reader_rng.fill_bytes(& mut v[read..]); - read += v.len() as usize; + reader_rng.fill_bytes(&mut v[read..]); + read += v.len(); } else { panic!("unexpected getrandom error: {}", err); } @@ -281,7 +282,7 @@ mod imp { } fn fill_bytes(&mut self, v: &mut [u8]) { let ret = unsafe { - SecRandomCopyBytes(kSecRandomDefault, v.len() as size_t, + SecRandomCopyBytes(kSecRandomDefault, v.len(), v.as_mut_ptr()) }; if ret == -1 { @@ -339,3 +340,66 @@ mod imp { } } } + +#[cfg(target_os = "fuchsia")] +mod imp { + use super::{next_u32, next_u64}; + + use io; + use rand::Rng; + + #[link(name = "magenta")] + extern { + fn mx_cprng_draw(buffer: *mut u8, len: usize, actual: *mut usize) -> i32; + } + + fn getrandom(buf: &mut [u8]) -> Result { + unsafe { + let mut actual = 0; + let status = mx_cprng_draw(buf.as_mut_ptr(), buf.len(), &mut actual); + if status == 0 { + Ok(actual) + } else { + Err(status) + } + } + } + + pub struct OsRng { + // dummy field to ensure that this struct cannot be constructed outside + // of this module + _dummy: (), + } + + impl OsRng { + /// Create a new `OsRng`. + pub fn new() -> io::Result { + Ok(OsRng { _dummy: () }) + } + } + + impl Rng for OsRng { + fn next_u32(&mut self) -> u32 { + next_u32(&mut |v| self.fill_bytes(v)) + } + fn next_u64(&mut self) -> u64 { + next_u64(&mut |v| self.fill_bytes(v)) + } + fn fill_bytes(&mut self, v: &mut [u8]) { + let mut buf = v; + while !buf.is_empty() { + let ret = getrandom(buf); + match ret { + Err(err) => { + panic!("kernel mx_cprng_draw call failed! (returned {}, buf.len() {})", + err, buf.len()) + } + Ok(actual) => { + let move_buf = buf; + buf = &mut move_buf[(actual as usize)..]; + } + } + } + } + } +} diff --git a/src/libstd/sys/unix/stdio.rs b/src/libstd/sys/unix/stdio.rs index 972bdbc381..273341b191 100644 --- a/src/libstd/sys/unix/stdio.rs +++ b/src/libstd/sys/unix/stdio.rs @@ -65,3 +65,6 @@ impl io::Write for Stderr { } fn flush(&mut self) -> io::Result<()> { Ok(()) } } + +pub const EBADF_ERR: i32 = ::libc::EBADF as i32; +pub const STDIN_BUF_SIZE: usize = ::sys_common::io::DEFAULT_BUF_SIZE; diff --git a/src/libstd/sys/unix/thread.rs b/src/libstd/sys/unix/thread.rs index 980ef01f54..1642baa34d 100644 --- a/src/libstd/sys/unix/thread.rs +++ b/src/libstd/sys/unix/thread.rs @@ -29,6 +29,20 @@ pub struct Thread { unsafe impl Send for Thread {} unsafe impl Sync for Thread {} +// The pthread_attr_setstacksize symbol doesn't exist in the emscripten libc, +// so we have to not link to it to satisfy emcc's ERROR_ON_UNDEFINED_SYMBOLS. +#[cfg(not(target_os = "emscripten"))] +unsafe fn pthread_attr_setstacksize(attr: *mut libc::pthread_attr_t, + stack_size: libc::size_t) -> libc::c_int { + libc::pthread_attr_setstacksize(attr, stack_size) +} + +#[cfg(target_os = "emscripten")] +unsafe fn pthread_attr_setstacksize(_attr: *mut libc::pthread_attr_t, + _stack_size: libc::size_t) -> libc::c_int { + panic!() +} + impl Thread { pub unsafe fn new<'a>(stack: usize, p: Box) -> io::Result { @@ -38,8 +52,8 @@ impl Thread { assert_eq!(libc::pthread_attr_init(&mut attr), 0); let stack_size = cmp::max(stack, min_stack_size(&attr)); - match libc::pthread_attr_setstacksize(&mut attr, - stack_size as libc::size_t) { + match pthread_attr_setstacksize(&mut attr, + stack_size) { 0 => {} n => { assert_eq!(n, libc::EINVAL); @@ -50,7 +64,6 @@ impl Thread { let page_size = os::page_size(); let stack_size = (stack_size + page_size - 1) & (-(page_size as isize - 1) as usize - 1); - let stack_size = stack_size as libc::size_t; assert_eq!(libc::pthread_attr_setstacksize(&mut attr, stack_size), 0); } @@ -122,6 +135,10 @@ impl Thread { pub fn set_name(_name: &CStr) { // Newlib, Illumos, Haiku, and Emscripten have no way to set a thread name. } + #[cfg(target_os = "fuchsia")] + pub fn set_name(_name: &CStr) { + // FIXME: determine whether Fuchsia has a way to set a thread name. + } pub fn sleep(dur: Duration) { let mut secs = dur.as_secs(); @@ -250,12 +267,8 @@ pub mod guard { // Rellocate the last page of the stack. // This ensures SIGBUS will be raised on // stack overflow. - let result = mmap(stackaddr, - psize as libc::size_t, - PROT_NONE, - MAP_PRIVATE | MAP_ANON | MAP_FIXED, - -1, - 0); + let result = mmap(stackaddr, psize, PROT_NONE, + MAP_PRIVATE | MAP_ANON | MAP_FIXED, -1, 0); if result != stackaddr || result == MAP_FAILED { panic!("failed to allocate a guard page"); @@ -279,8 +292,8 @@ pub mod guard { #[cfg(target_os = "macos")] pub unsafe fn current() -> Option { - Some((libc::pthread_get_stackaddr_np(libc::pthread_self()) as libc::size_t - - libc::pthread_get_stacksize_np(libc::pthread_self())) as usize) + Some((libc::pthread_get_stackaddr_np(libc::pthread_self()) as usize - + libc::pthread_get_stacksize_np(libc::pthread_self()))) } #[cfg(any(target_os = "openbsd", target_os = "bitrig"))] @@ -292,10 +305,10 @@ pub mod guard { let extra = if cfg!(target_os = "bitrig") {3} else {1} * os::page_size(); Some(if libc::pthread_main_np() == 1 { // main thread - current_stack.ss_sp as usize - current_stack.ss_size as usize + extra + current_stack.ss_sp as usize - current_stack.ss_size + extra } else { // new thread - current_stack.ss_sp as usize - current_stack.ss_size as usize + current_stack.ss_sp as usize - current_stack.ss_size }) } @@ -321,11 +334,11 @@ pub mod guard { &mut size), 0); ret = if cfg!(target_os = "freebsd") { - Some(stackaddr as usize - guardsize as usize) + Some(stackaddr as usize - guardsize) } else if cfg!(target_os = "netbsd") { Some(stackaddr as usize) } else { - Some(stackaddr as usize + guardsize as usize) + Some(stackaddr as usize + guardsize) }; } assert_eq!(libc::pthread_attr_destroy(&mut attr), 0); @@ -344,8 +357,8 @@ fn min_stack_size(attr: *const libc::pthread_attr_t) -> usize { weak!(fn __pthread_get_minstack(*const libc::pthread_attr_t) -> libc::size_t); match __pthread_get_minstack.get() { - None => libc::PTHREAD_STACK_MIN as usize, - Some(f) => unsafe { f(attr) as usize }, + None => libc::PTHREAD_STACK_MIN, + Some(f) => unsafe { f(attr) }, } } @@ -354,7 +367,7 @@ fn min_stack_size(attr: *const libc::pthread_attr_t) -> usize { #[cfg(all(not(target_os = "linux"), not(target_os = "netbsd")))] fn min_stack_size(_: *const libc::pthread_attr_t) -> usize { - libc::PTHREAD_STACK_MIN as usize + libc::PTHREAD_STACK_MIN } #[cfg(target_os = "netbsd")] diff --git a/src/libstd/sys/windows/args.rs b/src/libstd/sys/windows/args.rs new file mode 100644 index 0000000000..aa61f9adb8 --- /dev/null +++ b/src/libstd/sys/windows/args.rs @@ -0,0 +1,76 @@ +// 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. + +#![allow(dead_code)] // runtime init functions not used during testing + +use os::windows::prelude::*; +use sys::c; +use slice; +use ops::Range; +use ffi::OsString; +use libc::{c_int, c_void}; + +pub unsafe fn init(_argc: isize, _argv: *const *const u8) { } + +pub unsafe fn cleanup() { } + +pub fn args() -> Args { + unsafe { + let mut nArgs: c_int = 0; + let lpCmdLine = c::GetCommandLineW(); + let szArgList = c::CommandLineToArgvW(lpCmdLine, &mut nArgs); + + // szArcList can be NULL if CommandLinToArgvW failed, + // but in that case nArgs is 0 so we won't actually + // try to read a null pointer + Args { cur: szArgList, range: 0..(nArgs as isize) } + } +} + +pub struct Args { + range: Range, + cur: *mut *mut u16, +} + +unsafe fn os_string_from_ptr(ptr: *mut u16) -> OsString { + let mut len = 0; + while *ptr.offset(len) != 0 { len += 1; } + + // Push it onto the list. + let ptr = ptr as *const u16; + let buf = slice::from_raw_parts(ptr, len as usize); + OsStringExt::from_wide(buf) +} + +impl Iterator for Args { + type Item = OsString; + fn next(&mut self) -> Option { + self.range.next().map(|i| unsafe { os_string_from_ptr(*self.cur.offset(i)) } ) + } + fn size_hint(&self) -> (usize, Option) { self.range.size_hint() } +} + +impl DoubleEndedIterator for Args { + fn next_back(&mut self) -> Option { + self.range.next_back().map(|i| unsafe { os_string_from_ptr(*self.cur.offset(i)) } ) + } +} + +impl ExactSizeIterator for Args { + fn len(&self) -> usize { self.range.len() } +} + +impl Drop for Args { + fn drop(&mut self) { + // self.cur can be null if CommandLineToArgvW previously failed, + // but LocalFree ignores NULL pointers + unsafe { c::LocalFree(self.cur as *mut c_void); } + } +} diff --git a/src/libstd/sys/windows/env.rs b/src/libstd/sys/windows/env.rs new file mode 100644 index 0000000000..e6d7489577 --- /dev/null +++ b/src/libstd/sys/windows/env.rs @@ -0,0 +1,19 @@ +// 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. + +pub mod os { + pub const FAMILY: &'static str = "windows"; + pub const OS: &'static str = "windows"; + pub const DLL_PREFIX: &'static str = ""; + pub const DLL_SUFFIX: &'static str = ".dll"; + pub const DLL_EXTENSION: &'static str = "dll"; + pub const EXE_SUFFIX: &'static str = ".exe"; + pub const EXE_EXTENSION: &'static str = "exe"; +} diff --git a/src/libstd/sys/windows/ext/fs.rs b/src/libstd/sys/windows/ext/fs.rs index 4388a0bdff..1e2b8bf38f 100644 --- a/src/libstd/sys/windows/ext/fs.rs +++ b/src/libstd/sys/windows/ext/fs.rs @@ -12,12 +12,61 @@ #![stable(feature = "rust1", since = "1.0.0")] -use fs::{OpenOptions, Metadata}; +use fs::{self, OpenOptions, Metadata}; use io; use path::Path; use sys; use sys_common::{AsInnerMut, AsInner}; +/// Windows-specific extensions to `File` +#[unstable(feature = "file_offset", issue = "35918")] +pub trait FileExt { + /// Seeks to a given position and reads a number of bytes. + /// + /// Returns the number of bytes read. + /// + /// The offset is relative to the start of the file and thus independent + /// from the current cursor. The current cursor **is** affected by this + /// function, it is set to the end of the read. + /// + /// Reading beyond the end of the file will always return with a length of + /// 0. + /// + /// Note that similar to `File::read`, it is not an error to return with a + /// short read. When returning from such a short read, the file pointer is + /// still updated. + #[unstable(feature = "file_offset", issue = "35918")] + fn seek_read(&self, buf: &mut [u8], offset: u64) -> io::Result; + + /// Seeks to a given position and writes a number of bytes. + /// + /// Returns the number of bytes written. + /// + /// The offset is relative to the start of the file and thus independent + /// from the current cursor. The current cursor **is** affected by this + /// function, it is set to the end of the write. + /// + /// When writing beyond the end of the file, the file is appropiately + /// extended and the intermediate bytes are left uninitialized. + /// + /// Note that similar to `File::write`, it is not an error to return a + /// short write. When returning from such a short write, the file pointer + /// is still updated. + #[unstable(feature = "file_offset", issue = "35918")] + fn seek_write(&self, buf: &[u8], offset: u64) -> io::Result; +} + +#[unstable(feature = "file_offset", issue = "35918")] +impl FileExt for fs::File { + fn seek_read(&self, buf: &mut [u8], offset: u64) -> io::Result { + self.as_inner().read_at(buf, offset) + } + + fn seek_write(&self, buf: &[u8], offset: u64) -> io::Result { + self.as_inner().write_at(buf, offset) + } +} + /// Windows-specific extensions to `OpenOptions` #[stable(feature = "open_options_ext", since = "1.10.0")] pub trait OpenOptionsExt { diff --git a/src/libstd/sys/windows/ext/mod.rs b/src/libstd/sys/windows/ext/mod.rs index c3578fdfdb..932bb5e956 100644 --- a/src/libstd/sys/windows/ext/mod.rs +++ b/src/libstd/sys/windows/ext/mod.rs @@ -36,4 +36,6 @@ pub mod prelude { pub use super::ffi::{OsStrExt, OsStringExt}; #[doc(no_inline)] #[stable(feature = "rust1", since = "1.0.0")] pub use super::fs::{OpenOptionsExt, MetadataExt}; + #[doc(no_inline)] #[unstable(feature = "file_offset", issue = "35918")] + pub use super::fs::FileExt; } diff --git a/src/libstd/sys/windows/ext/process.rs b/src/libstd/sys/windows/ext/process.rs index 98166bf8cd..bce32959a2 100644 --- a/src/libstd/sys/windows/ext/process.rs +++ b/src/libstd/sys/windows/ext/process.rs @@ -33,7 +33,7 @@ impl AsRawHandle for process::Child { } } -#[stable(feature = "process_extensions", since = "1.2.0")] +#[stable(feature = "into_raw_os", since = "1.4.0")] impl IntoRawHandle for process::Child { fn into_raw_handle(self) -> RawHandle { self.into_inner().into_handle().into_raw() as *mut _ @@ -61,21 +61,21 @@ impl AsRawHandle for process::ChildStderr { } } -#[stable(feature = "process_extensions", since = "1.2.0")] +#[stable(feature = "into_raw_os", since = "1.4.0")] impl IntoRawHandle for process::ChildStdin { fn into_raw_handle(self) -> RawHandle { self.into_inner().into_handle().into_raw() as *mut _ } } -#[stable(feature = "process_extensions", since = "1.2.0")] +#[stable(feature = "into_raw_os", since = "1.4.0")] impl IntoRawHandle for process::ChildStdout { fn into_raw_handle(self) -> RawHandle { self.into_inner().into_handle().into_raw() as *mut _ } } -#[stable(feature = "process_extensions", since = "1.2.0")] +#[stable(feature = "into_raw_os", since = "1.4.0")] impl IntoRawHandle for process::ChildStderr { fn into_raw_handle(self) -> RawHandle { self.into_inner().into_handle().into_raw() as *mut _ @@ -91,7 +91,7 @@ pub trait ExitStatusExt { fn from_raw(raw: u32) -> Self; } -#[stable(feature = "rust1", since = "1.0.0")] +#[stable(feature = "exit_status_from", since = "1.12.0")] impl ExitStatusExt for process::ExitStatus { fn from_raw(raw: u32) -> Self { process::ExitStatus::from_inner(From::from(raw)) diff --git a/src/libstd/sys/windows/fs.rs b/src/libstd/sys/windows/fs.rs index 90a16853d5..98fd15f863 100644 --- a/src/libstd/sys/windows/fs.rs +++ b/src/libstd/sys/windows/fs.rs @@ -81,6 +81,14 @@ pub struct FilePermissions { attrs: c::DWORD } pub struct DirBuilder; +impl fmt::Debug for ReadDir { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + // This will only be called from std::fs::ReadDir, which will add a "ReadDir()" frame. + // Thus the result will be e g 'ReadDir("C:\")' + fmt::Debug::fmt(&*self.root, f) + } +} + impl Iterator for ReadDir { type Item = io::Result; fn next(&mut self) -> Option> { @@ -311,6 +319,10 @@ impl File { self.handle.read(buf) } + pub fn read_at(&self, buf: &mut [u8], offset: u64) -> io::Result { + self.handle.read_at(buf, offset) + } + pub fn read_to_end(&self, buf: &mut Vec) -> io::Result { self.handle.read_to_end(buf) } @@ -319,6 +331,10 @@ impl File { self.handle.write(buf) } + pub fn write_at(&self, buf: &[u8], offset: u64) -> io::Result { + self.handle.write_at(buf, offset) + } + pub fn flush(&self) -> io::Result<()> { Ok(()) } pub fn seek(&self, pos: SeekFrom) -> io::Result { diff --git a/src/libstd/sys/windows/handle.rs b/src/libstd/sys/windows/handle.rs index 97e746ee34..10b86ba44b 100644 --- a/src/libstd/sys/windows/handle.rs +++ b/src/libstd/sys/windows/handle.rs @@ -104,6 +104,23 @@ impl RawHandle { } } + pub fn read_at(&self, buf: &mut [u8], offset: u64) -> io::Result { + let mut read = 0; + let len = cmp::min(buf.len(), ::max_value() as usize) as c::DWORD; + let res = unsafe { + let mut overlapped: c::OVERLAPPED = mem::zeroed(); + overlapped.Offset = offset as u32; + overlapped.OffsetHigh = (offset >> 32) as u32; + cvt(c::ReadFile(self.0, buf.as_mut_ptr() as c::LPVOID, + len, &mut read, &mut overlapped)) + }; + match res { + Ok(_) => Ok(read as usize), + Err(ref e) if e.raw_os_error() == Some(c::ERROR_HANDLE_EOF as i32) => Ok(0), + Err(e) => Err(e), + } + } + pub unsafe fn read_overlapped(&self, buf: &mut [u8], overlapped: *mut c::OVERLAPPED) @@ -174,6 +191,19 @@ impl RawHandle { Ok(amt as usize) } + pub fn write_at(&self, buf: &[u8], offset: u64) -> io::Result { + let mut written = 0; + let len = cmp::min(buf.len(), ::max_value() as usize) as c::DWORD; + unsafe { + let mut overlapped: c::OVERLAPPED = mem::zeroed(); + overlapped.Offset = offset as u32; + overlapped.OffsetHigh = (offset >> 32) as u32; + cvt(c::WriteFile(self.0, buf.as_ptr() as c::LPVOID, + len, &mut written, &mut overlapped))?; + } + Ok(written as usize) + } + pub fn duplicate(&self, access: c::DWORD, inherit: bool, options: c::DWORD) -> io::Result { let mut ret = 0 as c::HANDLE; diff --git a/src/libstd/sys/windows/memchr.rs b/src/libstd/sys/windows/memchr.rs new file mode 100644 index 0000000000..5a5386acaa --- /dev/null +++ b/src/libstd/sys/windows/memchr.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. +// +// Original implementation taken from rust-memchr +// Copyright 2015 Andrew Gallant, bluss and Nicolas Koch + +// Fallback memchr is fastest on windows +pub use sys_common::memchr::fallback::{memchr, memrchr}; diff --git a/src/libstd/sys/windows/mod.rs b/src/libstd/sys/windows/mod.rs index 9741a704e8..defc41c5f4 100644 --- a/src/libstd/sys/windows/mod.rs +++ b/src/libstd/sys/windows/mod.rs @@ -18,17 +18,21 @@ use time::Duration; #[macro_use] pub mod compat; +pub mod args; pub mod backtrace; pub mod c; pub mod condvar; pub mod dynamic_lib; +pub mod env; pub mod ext; pub mod fs; pub mod handle; +pub mod memchr; pub mod mutex; pub mod net; pub mod os; pub mod os_str; +pub mod path; pub mod pipe; pub mod process; pub mod rand; @@ -175,7 +179,7 @@ pub fn truncate_utf16_at_nul<'a>(v: &'a [u16]) -> &'a [u16] { } } -trait IsZero { +pub trait IsZero { fn is_zero(&self) -> bool; } @@ -189,7 +193,7 @@ macro_rules! impl_is_zero { impl_is_zero! { i8 i16 i32 i64 isize u8 u16 u32 u64 usize } -fn cvt(i: I) -> io::Result { +pub fn cvt(i: I) -> io::Result { if i.is_zero() { Err(io::Error::last_os_error()) } else { @@ -197,7 +201,7 @@ fn cvt(i: I) -> io::Result { } } -fn dur2timeout(dur: Duration) -> c::DWORD { +pub fn dur2timeout(dur: Duration) -> c::DWORD { // Note that a duration is a (u64, u32) (seconds, nanoseconds) pair, and the // timeouts in windows APIs are typically u32 milliseconds. To translate, we // have two pieces to take care of: @@ -217,3 +221,17 @@ fn dur2timeout(dur: Duration) -> c::DWORD { } }).unwrap_or(c::INFINITE) } + +// On Windows, use the processor-specific __fastfail mechanism. In Windows 8 +// and later, this will terminate the process immediately without running any +// in-process exception handlers. In earlier versions of Windows, this +// sequence of instructions will be treated as an access violation, +// terminating the process but without necessarily bypassing all exception +// handlers. +// +// https://msdn.microsoft.com/en-us/library/dn774154.aspx +#[cfg(any(target_arch = "x86", target_arch = "x86_64"))] +pub unsafe fn abort_internal() -> ! { + asm!("int $$0x29" :: "{ecx}"(7) ::: volatile); // 7 is FAST_FAIL_FATAL_APP_EXIT + ::intrinsics::unreachable(); +} diff --git a/src/libstd/sys/windows/os.rs b/src/libstd/sys/windows/os.rs index 260fc3c4db..7e28dd1e25 100644 --- a/src/libstd/sys/windows/os.rs +++ b/src/libstd/sys/windows/os.rs @@ -18,8 +18,6 @@ use error::Error as StdError; use ffi::{OsString, OsStr}; use fmt; use io; -use libc::{c_int, c_void}; -use ops::Range; use os::windows::ffi::EncodeWide; use path::{self, PathBuf}; use ptr; @@ -272,60 +270,6 @@ pub fn unsetenv(n: &OsStr) -> io::Result<()> { }).map(|_| ()) } -pub struct Args { - range: Range, - cur: *mut *mut u16, -} - -unsafe fn os_string_from_ptr(ptr: *mut u16) -> OsString { - let mut len = 0; - while *ptr.offset(len) != 0 { len += 1; } - - // Push it onto the list. - let ptr = ptr as *const u16; - let buf = slice::from_raw_parts(ptr, len as usize); - OsStringExt::from_wide(buf) -} - -impl Iterator for Args { - type Item = OsString; - fn next(&mut self) -> Option { - self.range.next().map(|i| unsafe { os_string_from_ptr(*self.cur.offset(i)) } ) - } - fn size_hint(&self) -> (usize, Option) { self.range.size_hint() } -} - -impl DoubleEndedIterator for Args { - fn next_back(&mut self) -> Option { - self.range.next_back().map(|i| unsafe { os_string_from_ptr(*self.cur.offset(i)) } ) - } -} - -impl ExactSizeIterator for Args { - fn len(&self) -> usize { self.range.len() } -} - -impl Drop for Args { - fn drop(&mut self) { - // self.cur can be null if CommandLineToArgvW previously failed, - // but LocalFree ignores NULL pointers - unsafe { c::LocalFree(self.cur as *mut c_void); } - } -} - -pub fn args() -> Args { - unsafe { - let mut nArgs: c_int = 0; - let lpCmdLine = c::GetCommandLineW(); - let szArgList = c::CommandLineToArgvW(lpCmdLine, &mut nArgs); - - // szArcList can be NULL if CommandLinToArgvW failed, - // but in that case nArgs is 0 so we won't actually - // try to read a null pointer - Args { cur: szArgList, range: 0..(nArgs as isize) } - } -} - pub fn temp_dir() -> PathBuf { super::fill_utf16_buf(|buf, sz| unsafe { c::GetTempPathW(sz, buf) diff --git a/src/libstd/sys/windows/path.rs b/src/libstd/sys/windows/path.rs new file mode 100644 index 0000000000..2b47808451 --- /dev/null +++ b/src/libstd/sys/windows/path.rs @@ -0,0 +1,108 @@ +// 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 ascii::*; + +use path::Prefix; +use ffi::OsStr; +use mem; + +fn os_str_as_u8_slice(s: &OsStr) -> &[u8] { + unsafe { mem::transmute(s) } +} +unsafe fn u8_slice_as_os_str(s: &[u8]) -> &OsStr { + mem::transmute(s) +} + +#[inline] +pub fn is_sep_byte(b: u8) -> bool { + b == b'/' || b == b'\\' +} + +#[inline] +pub fn is_verbatim_sep(b: u8) -> bool { + b == b'\\' +} + +pub fn parse_prefix<'a>(path: &'a OsStr) -> Option { + use path::Prefix::*; + unsafe { + // The unsafety here stems from converting between &OsStr and &[u8] + // and back. This is safe to do because (1) we only look at ASCII + // contents of the encoding and (2) new &OsStr values are produced + // only from ASCII-bounded slices of existing &OsStr values. + let mut path = os_str_as_u8_slice(path); + + if path.starts_with(br"\\") { + // \\ + path = &path[2..]; + if path.starts_with(br"?\") { + // \\?\ + path = &path[2..]; + if path.starts_with(br"UNC\") { + // \\?\UNC\server\share + path = &path[4..]; + let (server, share) = match parse_two_comps(path, is_verbatim_sep) { + Some((server, share)) => + (u8_slice_as_os_str(server), u8_slice_as_os_str(share)), + None => (u8_slice_as_os_str(path), u8_slice_as_os_str(&[])), + }; + return Some(VerbatimUNC(server, share)); + } else { + // \\?\path + let idx = path.iter().position(|&b| b == b'\\'); + if idx == Some(2) && path[1] == b':' { + let c = path[0]; + if c.is_ascii() && (c as char).is_alphabetic() { + // \\?\C:\ path + return Some(VerbatimDisk(c.to_ascii_uppercase())); + } + } + let slice = &path[..idx.unwrap_or(path.len())]; + return Some(Verbatim(u8_slice_as_os_str(slice))); + } + } else if path.starts_with(b".\\") { + // \\.\path + path = &path[2..]; + let pos = path.iter().position(|&b| b == b'\\'); + let slice = &path[..pos.unwrap_or(path.len())]; + return Some(DeviceNS(u8_slice_as_os_str(slice))); + } + match parse_two_comps(path, is_sep_byte) { + 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))); + } + _ => (), + } + } else if path.get(1) == Some(& b':') { + // C: + let c = path[0]; + if c.is_ascii() && (c as char).is_alphabetic() { + return Some(Disk(c.to_ascii_uppercase())); + } + } + return None; + } + + fn parse_two_comps(mut path: &[u8], f: fn(u8) -> bool) -> Option<(&[u8], &[u8])> { + let first = match path.iter().position(|x| f(*x)) { + None => return None, + Some(x) => &path[..x], + }; + path = &path[(first.len() + 1)..]; + let idx = path.iter().position(|x| f(*x)); + let second = &path[..idx.unwrap_or(path.len())]; + Some((first, second)) + } +} + +pub const MAIN_SEP_STR: &'static str = "\\"; +pub const MAIN_SEP: char = '\\'; diff --git a/src/libstd/sys/windows/stdio.rs b/src/libstd/sys/windows/stdio.rs index 01249f05f6..72788776de 100644 --- a/src/libstd/sys/windows/stdio.rs +++ b/src/libstd/sys/windows/stdio.rs @@ -205,3 +205,10 @@ impl Output { fn invalid_encoding() -> io::Error { io::Error::new(io::ErrorKind::InvalidData, "text was not valid unicode") } + +pub const EBADF_ERR: i32 = ::sys::c::ERROR_INVALID_HANDLE as i32; +// 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. +pub const STDIN_BUF_SIZE: usize = 8 * 1024; diff --git a/src/libstd/sys/common/at_exit_imp.rs b/src/libstd/sys_common/at_exit_imp.rs similarity index 100% rename from src/libstd/sys/common/at_exit_imp.rs rename to src/libstd/sys_common/at_exit_imp.rs diff --git a/src/libstd/sys/common/backtrace.rs b/src/libstd/sys_common/backtrace.rs similarity index 100% rename from src/libstd/sys/common/backtrace.rs rename to src/libstd/sys_common/backtrace.rs diff --git a/src/libstd/sys/common/condvar.rs b/src/libstd/sys_common/condvar.rs similarity index 100% rename from src/libstd/sys/common/condvar.rs rename to src/libstd/sys_common/condvar.rs diff --git a/src/libstd/sys/common/gnu/libbacktrace.rs b/src/libstd/sys_common/gnu/libbacktrace.rs similarity index 100% rename from src/libstd/sys/common/gnu/libbacktrace.rs rename to src/libstd/sys_common/gnu/libbacktrace.rs diff --git a/src/libstd/sys/common/gnu/mod.rs b/src/libstd/sys_common/gnu/mod.rs similarity index 100% rename from src/libstd/sys/common/gnu/mod.rs rename to src/libstd/sys_common/gnu/mod.rs diff --git a/src/libstd/sys/common/io.rs b/src/libstd/sys_common/io.rs similarity index 97% rename from src/libstd/sys/common/io.rs rename to src/libstd/sys_common/io.rs index 3cd70eddb8..23daeeb518 100644 --- a/src/libstd/sys/common/io.rs +++ b/src/libstd/sys_common/io.rs @@ -12,6 +12,8 @@ use io::ErrorKind; use io::Read; use slice::from_raw_parts_mut; +pub const DEFAULT_BUF_SIZE: usize = 8 * 1024; + // Provides read_to_end functionality over an uninitialized buffer. // This function is unsafe because it calls the underlying // read function with a slice into uninitialized memory. The default @@ -51,6 +53,7 @@ pub unsafe fn read_to_end_uninitialized(r: &mut Read, buf: &mut Vec) -> io:: } #[cfg(test)] +#[allow(dead_code)] // not used on emscripten pub mod test { use path::{Path, PathBuf}; use env; @@ -165,6 +168,7 @@ mod tests { } #[bench] + #[cfg_attr(target_os = "emscripten", ignore)] fn bench_uninitialized(b: &mut ::test::Bencher) { b.iter(|| { let mut lr = repeat(1).take(10000000); diff --git a/src/libstd/sys_common/memchr.rs b/src/libstd/sys_common/memchr.rs new file mode 100644 index 0000000000..3824a5fb52 --- /dev/null +++ b/src/libstd/sys_common/memchr.rs @@ -0,0 +1,230 @@ +// 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. +// +// Original implementation taken from rust-memchr +// Copyright 2015 Andrew Gallant, bluss and Nicolas Koch + +#[allow(dead_code)] +pub mod fallback { + use cmp; + use mem; + + const LO_U64: u64 = 0x0101010101010101; + const HI_U64: u64 = 0x8080808080808080; + + // use truncation + const LO_USIZE: usize = LO_U64 as usize; + const HI_USIZE: usize = HI_U64 as usize; + + /// Return `true` if `x` contains any zero byte. + /// + /// From *Matters Computational*, J. Arndt + /// + /// "The idea is to subtract one from each of the bytes and then look for + /// bytes where the borrow propagated all the way to the most significant + /// bit." + #[inline] + fn contains_zero_byte(x: usize) -> bool { + x.wrapping_sub(LO_USIZE) & !x & HI_USIZE != 0 + } + + #[cfg(target_pointer_width = "32")] + #[inline] + fn repeat_byte(b: u8) -> usize { + let mut rep = (b as usize) << 8 | b as usize; + rep = rep << 16 | rep; + rep + } + + #[cfg(target_pointer_width = "64")] + #[inline] + fn repeat_byte(b: u8) -> usize { + let mut rep = (b as usize) << 8 | b as usize; + rep = rep << 16 | rep; + rep = rep << 32 | rep; + rep + } + + /// Return the first index matching the byte `a` in `text`. + pub fn memchr(x: u8, text: &[u8]) -> Option { + // Scan for a single byte value by reading two `usize` words at a time. + // + // Split `text` in three parts + // - unaligned initial part, before the first word aligned address in text + // - body, scan by 2 words at a time + // - the last remaining part, < 2 word size + let len = text.len(); + let ptr = text.as_ptr(); + let usize_bytes = mem::size_of::(); + + // search up to an aligned boundary + let align = (ptr as usize) & (usize_bytes- 1); + let mut offset; + if align > 0 { + offset = cmp::min(usize_bytes - align, len); + if let Some(index) = text[..offset].iter().position(|elt| *elt == x) { + return Some(index); + } + } else { + offset = 0; + } + + // search the body of the text + let repeated_x = repeat_byte(x); + + if len >= 2 * usize_bytes { + while offset <= len - 2 * usize_bytes { + unsafe { + let u = *(ptr.offset(offset as isize) as *const usize); + let v = *(ptr.offset((offset + usize_bytes) as isize) as *const usize); + + // break if there is a matching byte + let zu = contains_zero_byte(u ^ repeated_x); + let zv = contains_zero_byte(v ^ repeated_x); + if zu || zv { + break; + } + } + offset += usize_bytes * 2; + } + } + + // find the byte after the point the body loop stopped + text[offset..].iter().position(|elt| *elt == x).map(|i| offset + i) + } + + /// Return the last index matching the byte `a` in `text`. + pub fn memrchr(x: u8, text: &[u8]) -> Option { + // Scan for a single byte value by reading two `usize` words at a time. + // + // Split `text` in three parts + // - unaligned tail, after the last word aligned address in text + // - body, scan by 2 words at a time + // - the first remaining bytes, < 2 word size + let len = text.len(); + let ptr = text.as_ptr(); + let usize_bytes = mem::size_of::(); + + // search to an aligned boundary + let end_align = (ptr as usize + len) & (usize_bytes - 1); + let mut offset; + if end_align > 0 { + offset = if end_align >= len { 0 } else { len - end_align }; + if let Some(index) = text[offset..].iter().rposition(|elt| *elt == x) { + return Some(offset + index); + } + } else { + offset = len; + } + + // search the body of the text + let repeated_x = repeat_byte(x); + + while offset >= 2 * usize_bytes { + unsafe { + let u = *(ptr.offset(offset as isize - 2 * usize_bytes as isize) as *const usize); + let v = *(ptr.offset(offset as isize - usize_bytes as isize) as *const usize); + + // break if there is a matching byte + let zu = contains_zero_byte(u ^ repeated_x); + let zv = contains_zero_byte(v ^ repeated_x); + if zu || zv { + break; + } + } + offset -= 2 * usize_bytes; + } + + // find the byte before the point the body loop stopped + text[..offset].iter().rposition(|elt| *elt == x) + } + + // test fallback implementations on all platforms + #[test] + fn matches_one() { + assert_eq!(Some(0), memchr(b'a', b"a")); + } + + #[test] + fn matches_begin() { + assert_eq!(Some(0), memchr(b'a', b"aaaa")); + } + + #[test] + fn matches_end() { + assert_eq!(Some(4), memchr(b'z', b"aaaaz")); + } + + #[test] + fn matches_nul() { + assert_eq!(Some(4), memchr(b'\x00', b"aaaa\x00")); + } + + #[test] + fn matches_past_nul() { + assert_eq!(Some(5), memchr(b'z', b"aaaa\x00z")); + } + + #[test] + fn no_match_empty() { + assert_eq!(None, memchr(b'a', b"")); + } + + #[test] + fn no_match() { + assert_eq!(None, memchr(b'a', b"xyz")); + } + + #[test] + fn matches_one_reversed() { + assert_eq!(Some(0), memrchr(b'a', b"a")); + } + + #[test] + fn matches_begin_reversed() { + assert_eq!(Some(3), memrchr(b'a', b"aaaa")); + } + + #[test] + fn matches_end_reversed() { + assert_eq!(Some(0), memrchr(b'z', b"zaaaa")); + } + + #[test] + fn matches_nul_reversed() { + assert_eq!(Some(4), memrchr(b'\x00', b"aaaa\x00")); + } + + #[test] + fn matches_past_nul_reversed() { + assert_eq!(Some(0), memrchr(b'z', b"z\x00aaaa")); + } + + #[test] + fn no_match_empty_reversed() { + assert_eq!(None, memrchr(b'a', b"")); + } + + #[test] + fn no_match_reversed() { + assert_eq!(None, memrchr(b'a', b"xyz")); + } + + #[test] + fn each_alignment_reversed() { + let mut data = [1u8; 64]; + let needle = 2; + let pos = 40; + data[pos] = needle; + for start in 0..16 { + assert_eq!(Some(pos - start), memrchr(needle, &data[start..])); + } + } +} diff --git a/src/libstd/sys/common/mod.rs b/src/libstd/sys_common/mod.rs similarity index 82% rename from src/libstd/sys/common/mod.rs rename to src/libstd/sys_common/mod.rs index d1ca676510..1dd9b73e26 100644 --- a/src/libstd/sys/common/mod.rs +++ b/src/libstd/sys_common/mod.rs @@ -8,29 +8,31 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. +//! Platform-independent platform abstraction +//! +//! This is the platform-independent portion of the standard libraries +//! platform abstraction layer, whereas `std::sys` is the +//! platform-specific portion. +//! +//! The relationship between `std::sys_common`, `std::sys` and the +//! rest of `std` is complex, with dependencies going in all +//! directions: `std` depending on `sys_common`, `sys_common` +//! depending on `sys`, and `sys` depending on `sys_common` and `std`. +//! Ideally `sys_common` would be split into two and the dependencies +//! between them all would form a dag, facilitating the extraction of +//! `std::sys` from the standard library. + #![allow(missing_docs)] use sync::Once; use sys; -macro_rules! rtabort { - ($($t:tt)*) => (::sys_common::util::abort(format_args!($($t)*))) -} - -macro_rules! rtassert { - ($e:expr) => ({ - if !$e { - rtabort!(concat!("assertion failed: ", stringify!($e))) - } - }) -} - -pub mod args; pub mod at_exit_imp; #[cfg(any(not(cargobuild), feature = "backtrace"))] pub mod backtrace; pub mod condvar; pub mod io; +pub mod memchr; pub mod mutex; pub mod net; pub mod poison; @@ -87,11 +89,15 @@ pub fn at_exit(f: F) -> Result<(), ()> { if at_exit_imp::push(Box::new(f)) {Ok(())} else {Err(())} } +macro_rules! rtabort { + ($($t:tt)*) => (::sys_common::util::abort(format_args!($($t)*))) +} + /// One-time runtime cleanup. pub fn cleanup() { static CLEANUP: Once = Once::new(); CLEANUP.call_once(|| unsafe { - args::cleanup(); + sys::args::cleanup(); sys::stack_overflow::cleanup(); at_exit_imp::cleanup(); }); diff --git a/src/libstd/sys/common/mutex.rs b/src/libstd/sys_common/mutex.rs similarity index 100% rename from src/libstd/sys/common/mutex.rs rename to src/libstd/sys_common/mutex.rs diff --git a/src/libstd/sys/common/net.rs b/src/libstd/sys_common/net.rs similarity index 96% rename from src/libstd/sys/common/net.rs rename to src/libstd/sys_common/net.rs index 18280e497d..10ad61f4c8 100644 --- a/src/libstd/sys/common/net.rs +++ b/src/libstd/sys_common/net.rs @@ -29,7 +29,7 @@ use sys::net::netc::IPV6_JOIN_GROUP as IPV6_ADD_MEMBERSHIP; #[cfg(not(any(target_os = "dragonfly", target_os = "freebsd", target_os = "ios", target_os = "macos", target_os = "openbsd", target_os = "netbsd", - target_os = "solaris", taget_os = "haiku")))] + target_os = "solaris", target_os = "haiku")))] use sys::net::netc::IPV6_ADD_MEMBERSHIP; #[cfg(any(target_os = "dragonfly", target_os = "freebsd", target_os = "ios", target_os = "macos", @@ -42,6 +42,17 @@ use sys::net::netc::IPV6_LEAVE_GROUP as IPV6_DROP_MEMBERSHIP; target_os = "solaris", target_os = "haiku")))] use sys::net::netc::IPV6_DROP_MEMBERSHIP; +#[cfg(any(target_os = "linux", target_os = "android", + target_os = "dragonfly", target_os = "freebsd", + target_os = "openbsd", target_os = "netbsd", + target_os = "haiku", target_os = "bitrig"))] +use libc::MSG_NOSIGNAL; +#[cfg(not(any(target_os = "linux", target_os = "android", + target_os = "dragonfly", target_os = "freebsd", + target_os = "openbsd", target_os = "netbsd", + target_os = "haiku", target_os = "bitrig")))] +const MSG_NOSIGNAL: c_int = 0x0; + //////////////////////////////////////////////////////////////////////////////// // sockaddr and misc bindings //////////////////////////////////////////////////////////////////////////////// @@ -225,7 +236,7 @@ impl TcpStream { c::send(*self.inner.as_inner(), buf.as_ptr() as *const c_void, len, - 0) + MSG_NOSIGNAL) })?; Ok(ret as usize) } @@ -449,7 +460,7 @@ impl UdpSocket { let ret = cvt(unsafe { c::sendto(*self.inner.as_inner(), buf.as_ptr() as *const c_void, len, - 0, dstp, dstlen) + MSG_NOSIGNAL, dstp, dstlen) })?; Ok(ret as usize) } @@ -573,7 +584,7 @@ impl UdpSocket { c::send(*self.inner.as_inner(), buf.as_ptr() as *const c_void, len, - 0) + MSG_NOSIGNAL) })?; Ok(ret as usize) } diff --git a/src/libstd/sys/common/poison.rs b/src/libstd/sys_common/poison.rs similarity index 100% rename from src/libstd/sys/common/poison.rs rename to src/libstd/sys_common/poison.rs diff --git a/src/libstd/sys/common/remutex.rs b/src/libstd/sys_common/remutex.rs similarity index 99% rename from src/libstd/sys/common/remutex.rs rename to src/libstd/sys_common/remutex.rs index cbdeaad7f6..4d0407ccf6 100644 --- a/src/libstd/sys/common/remutex.rs +++ b/src/libstd/sys_common/remutex.rs @@ -156,7 +156,7 @@ impl<'a, T> Drop for ReentrantMutexGuard<'a, T> { } -#[cfg(test)] +#[cfg(all(test, not(target_os = "emscripten")))] mod tests { use sys_common::remutex::{ReentrantMutex, ReentrantMutexGuard}; use cell::RefCell; diff --git a/src/libstd/sys/common/rwlock.rs b/src/libstd/sys_common/rwlock.rs similarity index 100% rename from src/libstd/sys/common/rwlock.rs rename to src/libstd/sys_common/rwlock.rs diff --git a/src/libstd/sys/common/thread.rs b/src/libstd/sys_common/thread.rs similarity index 100% rename from src/libstd/sys/common/thread.rs rename to src/libstd/sys_common/thread.rs diff --git a/src/libstd/sys/common/thread_info.rs b/src/libstd/sys_common/thread_info.rs similarity index 100% rename from src/libstd/sys/common/thread_info.rs rename to src/libstd/sys_common/thread_info.rs diff --git a/src/libstd/sys/common/thread_local.rs b/src/libstd/sys_common/thread_local.rs similarity index 100% rename from src/libstd/sys/common/thread_local.rs rename to src/libstd/sys_common/thread_local.rs diff --git a/src/libstd/sys/common/util.rs b/src/libstd/sys_common/util.rs similarity index 58% rename from src/libstd/sys/common/util.rs rename to src/libstd/sys_common/util.rs index b5d0357633..daa0c15920 100644 --- a/src/libstd/sys/common/util.rs +++ b/src/libstd/sys_common/util.rs @@ -33,32 +33,6 @@ pub fn dumb_print(args: fmt::Arguments) { let _ = Stderr::new().map(|mut stderr| stderr.write_fmt(args)); } -// On Unix-like platforms, libc::abort will unregister signal handlers -// including the SIGABRT handler, preventing the abort from being blocked, and -// fclose streams, with the side effect of flushing them so libc bufferred -// output will be printed. Additionally the shell will generally print a more -// understandable error message like "Abort trap" rather than "Illegal -// instruction" that intrinsics::abort would cause, as intrinsics::abort is -// implemented as an illegal instruction. -#[cfg(unix)] -unsafe fn abort_internal() -> ! { - ::libc::abort() -} - -// On Windows, use the processor-specific __fastfail mechanism. In Windows 8 -// and later, this will terminate the process immediately without running any -// in-process exception handlers. In earlier versions of Windows, this -// sequence of instructions will be treated as an access violation, -// terminating the process but without necessarily bypassing all exception -// handlers. -// -// https://msdn.microsoft.com/en-us/library/dn774154.aspx -#[cfg(all(windows, any(target_arch = "x86", target_arch = "x86_64")))] -unsafe fn abort_internal() -> ! { - asm!("int $$0x29" :: "{ecx}"(7) ::: volatile); // 7 is FAST_FAIL_FATAL_APP_EXIT - ::intrinsics::unreachable(); -} - // Other platforms should use the appropriate platform-specific mechanism for // aborting the process. If no platform-specific mechanism is available, // ::intrinsics::abort() may be used instead. The above implementations cover @@ -66,7 +40,7 @@ unsafe fn abort_internal() -> ! { pub fn abort(args: fmt::Arguments) -> ! { dumb_print(format_args!("fatal runtime error: {}\n", args)); - unsafe { abort_internal(); } + unsafe { ::sys::abort_internal(); } } #[allow(dead_code)] // stack overflow detection not enabled on all platforms diff --git a/src/libstd/sys/common/wtf8.rs b/src/libstd/sys_common/wtf8.rs similarity index 98% rename from src/libstd/sys/common/wtf8.rs rename to src/libstd/sys_common/wtf8.rs index 8d357aa78c..0a94ff1e95 100644 --- a/src/libstd/sys/common/wtf8.rs +++ b/src/libstd/sys_common/wtf8.rs @@ -206,10 +206,12 @@ impl Wtf8Buf { /// Copied from String::push /// This does **not** include the WTF-8 concatenation check. fn push_code_point_unchecked(&mut self, code_point: CodePoint) { - let bytes = unsafe { - char::from_u32_unchecked(code_point.value).encode_utf8() + let c = unsafe { + char::from_u32_unchecked(code_point.value) }; - self.bytes.extend_from_slice(bytes.as_slice()); + let mut bytes = [0; 4]; + let bytes = c.encode_utf8(&mut bytes).as_bytes(); + self.bytes.extend_from_slice(bytes) } #[inline] @@ -738,15 +740,16 @@ impl<'a> Iterator for EncodeWide<'a> { return Some(tmp); } + let mut buf = [0; 2]; self.code_points.next().map(|code_point| { - let n = unsafe { - char::from_u32_unchecked(code_point.value).encode_utf16() + let c = unsafe { + char::from_u32_unchecked(code_point.value) }; - let n = n.as_slice(); - if n.len() == 2 { - self.extra = n[1]; + let n = c.encode_utf16(&mut buf).len(); + if n == 2 { + self.extra = buf[1]; } - n[0] + buf[0] }) } diff --git a/src/libstd/thread/local.rs b/src/libstd/thread/local.rs index c44dee49f1..f74dd59249 100644 --- a/src/libstd/thread/local.rs +++ b/src/libstd/thread/local.rs @@ -166,8 +166,8 @@ macro_rules! __thread_local_inner { { #[thread_local] #[cfg(target_thread_local)] - static __KEY: $crate::thread::__ElfLocalKeyInner<$t> = - $crate::thread::__ElfLocalKeyInner::new(); + static __KEY: $crate::thread::__FastLocalKeyInner<$t> = + $crate::thread::__FastLocalKeyInner::new(); #[cfg(not(target_thread_local))] static __KEY: $crate::thread::__OsLocalKeyInner<$t> = @@ -310,153 +310,6 @@ impl LocalKey { } } -#[cfg(target_thread_local)] -#[doc(hidden)] -pub mod elf { - use cell::{Cell, UnsafeCell}; - use intrinsics; - use ptr; - - pub struct Key { - inner: UnsafeCell>, - - // Metadata to keep track of the state of the destructor. Remember that - // these variables are thread-local, not global. - dtor_registered: Cell, - dtor_running: Cell, - } - - unsafe impl ::marker::Sync for Key { } - - impl Key { - pub const fn new() -> Key { - Key { - inner: UnsafeCell::new(None), - dtor_registered: Cell::new(false), - dtor_running: Cell::new(false) - } - } - - pub fn get(&'static self) -> Option<&'static UnsafeCell>> { - unsafe { - if intrinsics::needs_drop::() && self.dtor_running.get() { - return None - } - self.register_dtor(); - } - Some(&self.inner) - } - - unsafe fn register_dtor(&self) { - if !intrinsics::needs_drop::() || self.dtor_registered.get() { - return - } - - register_dtor(self as *const _ as *mut u8, - destroy_value::); - self.dtor_registered.set(true); - } - } - - // Since what appears to be glibc 2.18 this symbol has been shipped which - // GCC and clang both use to invoke destructors in thread_local globals, so - // let's do the same! - // - // Note, however, that we run on lots older linuxes, as well as cross - // compiling from a newer linux to an older linux, so we also have a - // fallback implementation to use as well. - // - // Due to rust-lang/rust#18804, make sure this is not generic! - #[cfg(target_os = "linux")] - unsafe fn register_dtor(t: *mut u8, dtor: unsafe extern fn(*mut u8)) { - use mem; - use libc; - use sys_common::thread_local as os; - - extern { - #[linkage = "extern_weak"] - static __dso_handle: *mut u8; - #[linkage = "extern_weak"] - static __cxa_thread_atexit_impl: *const libc::c_void; - } - if !__cxa_thread_atexit_impl.is_null() { - type F = unsafe extern fn(dtor: unsafe extern fn(*mut u8), - arg: *mut u8, - dso_handle: *mut u8) -> libc::c_int; - mem::transmute::<*const libc::c_void, F>(__cxa_thread_atexit_impl) - (dtor, t, &__dso_handle as *const _ as *mut _); - return - } - - // The fallback implementation uses a vanilla OS-based TLS key to track - // the list of destructors that need to be run for this thread. The key - // then has its own destructor which runs all the other destructors. - // - // The destructor for DTORS is a little special in that it has a `while` - // loop to continuously drain the list of registered destructors. It - // *should* be the case that this loop always terminates because we - // provide the guarantee that a TLS key cannot be set after it is - // flagged for destruction. - static DTORS: os::StaticKey = os::StaticKey::new(Some(run_dtors)); - type List = Vec<(*mut u8, unsafe extern fn(*mut u8))>; - if DTORS.get().is_null() { - let v: Box = box Vec::new(); - DTORS.set(Box::into_raw(v) as *mut u8); - } - let list: &mut List = &mut *(DTORS.get() as *mut List); - list.push((t, dtor)); - - unsafe extern fn run_dtors(mut ptr: *mut u8) { - while !ptr.is_null() { - let list: Box = Box::from_raw(ptr as *mut List); - for &(ptr, dtor) in list.iter() { - dtor(ptr); - } - ptr = DTORS.get(); - DTORS.set(ptr::null_mut()); - } - } - } - - // OSX's analog of the above linux function is this _tlv_atexit function. - // The disassembly of thread_local globals in C++ (at least produced by - // clang) will have this show up in the output. - #[cfg(target_os = "macos")] - unsafe fn register_dtor(t: *mut u8, dtor: unsafe extern fn(*mut u8)) { - extern { - fn _tlv_atexit(dtor: unsafe extern fn(*mut u8), - arg: *mut u8); - } - _tlv_atexit(dtor, t); - } - - pub unsafe extern fn destroy_value(ptr: *mut u8) { - let ptr = ptr as *mut Key; - // Right before we run the user destructor be sure to flag the - // destructor as running for this thread so calls to `get` will return - // `None`. - (*ptr).dtor_running.set(true); - - // The OSX implementation of TLS apparently had an odd aspect to it - // where the pointer we have may be overwritten while this destructor - // is running. Specifically if a TLS destructor re-accesses TLS it may - // trigger a re-initialization of all TLS variables, paving over at - // least some destroyed ones with initial values. - // - // This means that if we drop a TLS value in place on OSX that we could - // revert the value to its original state halfway through the - // destructor, which would be bad! - // - // Hence, we use `ptr::read` on OSX (to move to a "safe" location) - // instead of drop_in_place. - if cfg!(target_os = "macos") { - ptr::read((*ptr).inner.get()); - } else { - ptr::drop_in_place((*ptr).inner.get()); - } - } -} - #[doc(hidden)] pub mod os { use cell::{Cell, UnsafeCell}; @@ -524,7 +377,7 @@ pub mod os { } } -#[cfg(test)] +#[cfg(all(test, not(target_os = "emscripten")))] mod tests { use sync::mpsc::{channel, Sender}; use cell::{Cell, UnsafeCell}; diff --git a/src/libstd/thread/mod.rs b/src/libstd/thread/mod.rs index d8e021bb04..255cd2a9bc 100644 --- a/src/libstd/thread/mod.rs +++ b/src/libstd/thread/mod.rs @@ -151,7 +151,7 @@ //! //! [`Cell`]: ../cell/struct.Cell.html //! [`RefCell`]: ../cell/struct.RefCell.html -//! [`thread_local!`]: ../macro.thread_local!.html +//! [`thread_local!`]: ../macro.thread_local.html //! [`with`]: struct.LocalKey.html#method.with #![stable(feature = "rust1", since = "1.0.0")] @@ -166,6 +166,7 @@ use panicking; use str; use sync::{Mutex, Condvar, Arc}; use sys::thread as imp; +use sys_common::mutex; use sys_common::thread_info; use sys_common::util; use sys_common::{AsInner, IntoInner}; @@ -180,9 +181,18 @@ use time::Duration; #[stable(feature = "rust1", since = "1.0.0")] pub use self::local::{LocalKey, LocalKeyState}; +// The types used by the thread_local! macro to access TLS keys. Note that there +// are two types, the "OS" type and the "fast" type. The OS thread local key +// type is accessed via platform-specific API calls and is slow, while the fast +// key type is accessed via code generated via LLVM, where TLS keys are set up +// by the elf linker. Note that the OS TLS type is always available: on macOS +// the standard library is compiled with support for older platform versions +// where fast TLS was not available; end-user code is compiled with fast TLS +// where available, but both are needed. + #[unstable(feature = "libstd_thread_internals", issue = "0")] #[cfg(target_thread_local)] -#[doc(hidden)] pub use self::local::elf::Key as __ElfLocalKeyInner; +#[doc(hidden)] pub use sys::fast_thread_local::Key as __FastLocalKeyInner; #[unstable(feature = "libstd_thread_internals", issue = "0")] #[doc(hidden)] pub use self::local::os::Key as __OsLocalKeyInner; @@ -524,6 +534,45 @@ pub fn park_timeout(dur: Duration) { *guard = false; } +//////////////////////////////////////////////////////////////////////////////// +// ThreadId +//////////////////////////////////////////////////////////////////////////////// + +/// A unique identifier for a running thread. +/// +/// A `ThreadId` is an opaque object that has a unique value for each thread +/// that creates one. `ThreadId`s do not correspond to a thread's system- +/// designated identifier. +#[unstable(feature = "thread_id", issue = "21507")] +#[derive(Eq, PartialEq, Copy, Clone)] +pub struct ThreadId(u64); + +impl ThreadId { + // Generate a new unique thread ID. + fn new() -> ThreadId { + static GUARD: mutex::Mutex = mutex::Mutex::new(); + static mut COUNTER: u64 = 0; + + unsafe { + GUARD.lock(); + + // If we somehow use up all our bits, panic so that we're not + // covering up subtle bugs of IDs being reused. + if COUNTER == ::u64::MAX { + GUARD.unlock(); + panic!("failed to generate unique thread ID: bitspace exhausted"); + } + + let id = COUNTER; + COUNTER += 1; + + GUARD.unlock(); + + ThreadId(id) + } + } +} + //////////////////////////////////////////////////////////////////////////////// // Thread //////////////////////////////////////////////////////////////////////////////// @@ -531,6 +580,7 @@ pub fn park_timeout(dur: Duration) { /// The internal representation of a `Thread` handle struct Inner { name: Option, // Guaranteed to be UTF-8 + id: ThreadId, lock: Mutex, // true when there is a buffered unpark cvar: Condvar, } @@ -551,6 +601,7 @@ impl Thread { Thread { inner: Arc::new(Inner { name: cname, + id: ThreadId::new(), lock: Mutex::new(false), cvar: Condvar::new(), }) @@ -569,6 +620,12 @@ impl Thread { } } + /// Gets the thread's unique identifier. + #[unstable(feature = "thread_id", issue = "21507")] + pub fn id(&self) -> ThreadId { + self.inner.id + } + /// Gets the thread's name. /// /// # Examples @@ -741,7 +798,7 @@ fn _assert_sync_and_send() { // Tests //////////////////////////////////////////////////////////////////////////////// -#[cfg(test)] +#[cfg(all(test, not(target_os = "emscripten")))] mod tests { use any::Any; use sync::mpsc::{channel, Sender}; @@ -977,6 +1034,17 @@ mod tests { thread::sleep(Duration::from_millis(2)); } + #[test] + fn test_thread_id_equal() { + assert!(thread::current().id() == thread::current().id()); + } + + #[test] + fn test_thread_id_not_equal() { + let spawned_id = thread::spawn(|| thread::current().id()).join().unwrap(); + assert!(thread::current().id() != spawned_id); + } + // NOTE: the corresponding test for stderr is in run-pass/thread-stderr, due // to the test harness apparently interfering with stderr configuration. } diff --git a/src/libstd/time/mod.rs b/src/libstd/time/mod.rs index 154f603c84..6854f1e14f 100644 --- a/src/libstd/time/mod.rs +++ b/src/libstd/time/mod.rs @@ -118,7 +118,7 @@ pub struct Instant(time::Instant); pub struct SystemTime(time::SystemTime); /// An error returned from the `duration_since` method on `SystemTime`, -/// used to learn about why how far in the opposite direction a timestamp lies. +/// used to learn how far in the opposite direction a system time lies. #[derive(Clone, Debug)] #[stable(feature = "time2", since = "1.8.0")] pub struct SystemTimeError(Duration); diff --git a/src/libsyntax/abi.rs b/src/libsyntax/abi.rs index 1f2dc228de..a39cac8db9 100644 --- a/src/libsyntax/abi.rs +++ b/src/libsyntax/abi.rs @@ -33,7 +33,7 @@ pub enum Abi { // NB: This ordering MUST match the AbiDatas array below. // (This is ensured by the test indices_are_correct().) - // Single platform ABIs come first (`for_arch()` relies on this) + // Single platform ABIs Cdecl, Stdcall, Fastcall, @@ -42,7 +42,7 @@ pub enum Abi { Win64, SysV64, - // Multiplatform ABIs second + // Multiplatform / generic ABIs Rust, C, System, @@ -65,41 +65,31 @@ pub enum Architecture { pub struct AbiData { abi: Abi, - // Name of this ABI as we like it called. + /// Name of this ABI as we like it called. name: &'static str, -} -#[derive(Copy, Clone)] -pub enum AbiArchitecture { - /// Not a real ABI (e.g., intrinsic) - Rust, - /// An ABI that specifies cross-platform defaults (e.g., "C") - All, - /// Multiple architectures (bitset) - Archs(u32) + /// A generic ABI is supported on all platforms. + generic: bool, } #[allow(non_upper_case_globals)] const AbiDatas: &'static [AbiData] = &[ // Platform-specific ABIs - AbiData {abi: Abi::Cdecl, name: "cdecl" }, - AbiData {abi: Abi::Stdcall, name: "stdcall" }, - AbiData {abi: Abi::Fastcall, name: "fastcall" }, - AbiData {abi: Abi::Vectorcall, name: "vectorcall"}, - AbiData {abi: Abi::Aapcs, name: "aapcs" }, - AbiData {abi: Abi::Win64, name: "win64" }, - AbiData {abi: Abi::SysV64, name: "sysv64" }, + AbiData {abi: Abi::Cdecl, name: "cdecl", generic: false }, + AbiData {abi: Abi::Stdcall, name: "stdcall", generic: false }, + AbiData {abi: Abi::Fastcall, name: "fastcall", generic: false }, + AbiData {abi: Abi::Vectorcall, name: "vectorcall", generic: false}, + AbiData {abi: Abi::Aapcs, name: "aapcs", generic: false }, + AbiData {abi: Abi::Win64, name: "win64", generic: false }, + AbiData {abi: Abi::SysV64, name: "sysv64", generic: false }, // Cross-platform ABIs - // - // NB: Do not adjust this ordering without - // adjusting the indices below. - AbiData {abi: Abi::Rust, name: "Rust" }, - AbiData {abi: Abi::C, name: "C" }, - AbiData {abi: Abi::System, name: "system" }, - AbiData {abi: Abi::RustIntrinsic, name: "rust-intrinsic" }, - AbiData {abi: Abi::RustCall, name: "rust-call" }, - AbiData {abi: Abi::PlatformIntrinsic, name: "platform-intrinsic" } + AbiData {abi: Abi::Rust, name: "Rust", generic: true }, + AbiData {abi: Abi::C, name: "C", generic: true }, + AbiData {abi: Abi::System, name: "system", generic: true }, + AbiData {abi: Abi::RustIntrinsic, name: "rust-intrinsic", generic: true }, + AbiData {abi: Abi::RustCall, name: "rust-call", generic: true }, + AbiData {abi: Abi::PlatformIntrinsic, name: "platform-intrinsic", generic: true }, ]; /// Returns the ABI with the given name (if any). @@ -125,6 +115,10 @@ impl Abi { pub fn name(&self) -> &'static str { self.data().name } + + pub fn generic(&self) -> bool { + self.data().generic + } } impl fmt::Display for Abi { diff --git a/src/libsyntax/ast.rs b/src/libsyntax/ast.rs index c18b36161d..f7581924eb 100644 --- a/src/libsyntax/ast.rs +++ b/src/libsyntax/ast.rs @@ -71,7 +71,7 @@ impl Encodable for Name { impl Decodable for Name { fn decode(d: &mut D) -> Result { - Ok(token::intern(&d.read_str()?[..])) + Ok(token::intern(&d.read_str()?)) } } @@ -121,6 +121,7 @@ impl fmt::Debug for Lifetime { /// A lifetime definition, e.g. `'a: 'b+'c+'d` #[derive(Clone, PartialEq, Eq, RustcEncodable, RustcDecodable, Hash, Debug)] pub struct LifetimeDef { + pub attrs: ThinVec, pub lifetime: Lifetime, pub bounds: Vec } @@ -160,12 +161,12 @@ impl Path { Path { span: s, global: false, - segments: vec!( + segments: vec![ PathSegment { identifier: identifier, parameters: PathParameters::none() } - ), + ], } } } @@ -370,6 +371,7 @@ pub type TyParamBounds = P<[TyParamBound]>; #[derive(Clone, PartialEq, Eq, RustcEncodable, RustcDecodable, Hash, Debug)] pub struct TyParam { + pub attrs: ThinVec, pub ident: Ident, pub id: NodeId, pub bounds: TyParamBounds, @@ -475,7 +477,6 @@ pub type CrateConfig = Vec>; pub struct Crate { pub module: Mod, pub attrs: Vec, - pub config: CrateConfig, pub span: Span, pub exported_macros: Vec, } @@ -593,7 +594,7 @@ impl Pat { PatKind::Box(ref s) | PatKind::Ref(ref s, _) => { s.walk(it) } - PatKind::Vec(ref before, ref slice, ref after) => { + PatKind::Slice(ref before, ref slice, ref after) => { before.iter().all(|p| p.walk(it)) && slice.iter().all(|p| p.walk(it)) && after.iter().all(|p| p.walk(it)) @@ -669,8 +670,8 @@ pub enum PatKind { /// A range pattern, e.g. `1...2` Range(P, P), /// `[a, b, ..i, y, z]` is represented as: - /// `PatKind::Vec(box [a, b], Some(i), box [y, z])` - Vec(Vec>, Option>, Vec>), + /// `PatKind::Slice(box [a, b], Some(i), box [y, z])` + Slice(Vec>, Option>, Vec>), /// A macro pattern; pre-expansion Mac(Mac), } @@ -898,6 +899,7 @@ pub struct Field { pub ident: SpannedIdent, pub expr: P, pub span: Span, + pub is_shorthand: bool, } pub type SpannedIdent = Spanned; @@ -1048,7 +1050,7 @@ pub enum ExprKind { Ret(Option>), /// Output of the `asm!()` macro - InlineAsm(InlineAsm), + InlineAsm(P), /// A macro invocation; pre-expansion Mac(Mac), @@ -1431,10 +1433,10 @@ pub struct BareFnTy { /// The different kinds of types recognized by the compiler #[derive(Clone, PartialEq, Eq, RustcEncodable, RustcDecodable, Hash, Debug)] pub enum TyKind { - /// A variable-length array (`[T]`) - Vec(P), + /// A variable-length slice (`[T]`) + Slice(P), /// A fixed length array (`[T; n]`) - FixedLengthVec(P, P), + Array(P, P), /// A raw pointer (`*const T` or `*mut T`) Ptr(MutTy), /// A reference (`&'a T` or `&'a mut T`) @@ -2010,8 +2012,6 @@ pub struct MacroDef { pub id: NodeId, pub span: Span, pub imported_from: Option, - pub export: bool, - pub use_locally: bool, pub allow_internal_unstable: bool, pub body: Vec, } diff --git a/src/libsyntax/attr.rs b/src/libsyntax/attr.rs index dc02c26039..0335f21034 100644 --- a/src/libsyntax/attr.rs +++ b/src/libsyntax/attr.rs @@ -501,10 +501,7 @@ pub fn requests_inline(attrs: &[Attribute]) -> bool { } /// Tests if a cfg-pattern matches the cfg set -pub fn cfg_matches(cfgs: &[P], cfg: &ast::MetaItem, - sess: &ParseSess, - features: Option<&Features>) - -> bool { +pub fn cfg_matches(cfg: &ast::MetaItem, sess: &ParseSess, features: Option<&Features>) -> bool { match cfg.node { ast::MetaItemKind::List(ref pred, ref mis) => { for mi in mis.iter() { @@ -518,10 +515,10 @@ pub fn cfg_matches(cfgs: &[P], cfg: &ast::MetaItem, // that they won't fail with the loop above. match &pred[..] { "any" => mis.iter().any(|mi| { - cfg_matches(cfgs, mi.meta_item().unwrap(), sess, features) + cfg_matches(mi.meta_item().unwrap(), sess, features) }), "all" => mis.iter().all(|mi| { - cfg_matches(cfgs, mi.meta_item().unwrap(), sess, features) + cfg_matches(mi.meta_item().unwrap(), sess, features) }), "not" => { if mis.len() != 1 { @@ -529,7 +526,7 @@ pub fn cfg_matches(cfgs: &[P], cfg: &ast::MetaItem, return false; } - !cfg_matches(cfgs, mis[0].meta_item().unwrap(), sess, features) + !cfg_matches(mis[0].meta_item().unwrap(), sess, features) }, p => { span_err!(sess.span_diagnostic, cfg.span, E0537, "invalid predicate `{}`", p); @@ -541,7 +538,7 @@ pub fn cfg_matches(cfgs: &[P], cfg: &ast::MetaItem, if let (Some(feats), Some(gated_cfg)) = (features, GatedCfg::gate(cfg)) { gated_cfg.check_and_emit(sess, feats); } - contains(cfgs, cfg) + contains(&sess.config, cfg) } } } diff --git a/src/libsyntax/codemap.rs b/src/libsyntax/codemap.rs index 6d68ce3646..49012ad036 100644 --- a/src/libsyntax/codemap.rs +++ b/src/libsyntax/codemap.rs @@ -804,7 +804,7 @@ impl CodeMap { } pub fn macro_backtrace(&self, span: Span) -> Vec { - let mut last_span = DUMMY_SP; + let mut prev_span = DUMMY_SP; let mut span = span; let mut result = vec![]; loop { @@ -827,14 +827,14 @@ impl CodeMap { None => break, Some((call_site, macro_decl_name, def_site_span)) => { // Don't print recursive invocations - if !call_site.source_equal(&last_span) { + if !call_site.source_equal(&prev_span) { result.push(MacroBacktrace { call_site: call_site, macro_decl_name: macro_decl_name, def_site_span: def_site_span, }); } - last_span = span; + prev_span = span; span = call_site; } } diff --git a/src/libsyntax/config.rs b/src/libsyntax/config.rs index f569b3271b..946257a16d 100644 --- a/src/libsyntax/config.rs +++ b/src/libsyntax/config.rs @@ -9,7 +9,7 @@ // except according to those terms. use attr::HasAttrs; -use feature_gate::{emit_feature_err, EXPLAIN_STMT_ATTR_SYNTAX, Features, get_features, GateIssue}; +use feature_gate::{feature_err, EXPLAIN_STMT_ATTR_SYNTAX, Features, get_features, GateIssue}; use {fold, attr}; use ast; use codemap::{Spanned, respan}; @@ -20,7 +20,6 @@ use util::small_vector::SmallVector; /// A folder that strips out items that do not belong in the current configuration. pub struct StripUnconfigured<'a> { - pub config: &'a ast::CrateConfig, pub should_test: bool, pub sess: &'a ParseSess, pub features: Option<&'a Features>, @@ -32,7 +31,6 @@ pub fn features(mut krate: ast::Crate, sess: &ParseSess, should_test: bool) let features; { let mut strip_unconfigured = StripUnconfigured { - config: &krate.config.clone(), should_test: should_test, sess: sess, features: None, @@ -107,7 +105,7 @@ impl<'a> StripUnconfigured<'a> { use attr::cfg_matches; match (cfg.meta_item(), mi.meta_item()) { (Some(cfg), Some(mi)) => - if cfg_matches(self.config, &cfg, self.sess, self.features) { + if cfg_matches(&cfg, self.sess, self.features) { self.process_cfg_attr(respan(mi.span, ast::Attribute_ { id: attr::mk_attr_id(), style: attr.node.style, @@ -148,7 +146,7 @@ impl<'a> StripUnconfigured<'a> { return true; } - attr::cfg_matches(self.config, mis[0].meta_item().unwrap(), self.sess, self.features) + attr::cfg_matches(mis[0].meta_item().unwrap(), self.sess, self.features) }) } @@ -157,11 +155,15 @@ impl<'a> StripUnconfigured<'a> { // flag the offending attributes for attr in attrs.iter() { if !self.features.map(|features| features.stmt_expr_attributes).unwrap_or(true) { - emit_feature_err(&self.sess, - "stmt_expr_attributes", - attr.span, - GateIssue::Language, - EXPLAIN_STMT_ATTR_SYNTAX); + let mut err = feature_err(&self.sess, + "stmt_expr_attributes", + attr.span, + GateIssue::Language, + EXPLAIN_STMT_ATTR_SYNTAX); + if attr.node.is_sugared_doc { + err.help("`///` is for documentation comments. For a plain comment, use `//`."); + } + err.emit(); } } } @@ -302,6 +304,6 @@ fn is_cfg(attr: &ast::Attribute) -> bool { attr.check_name("cfg") } -fn is_test_or_bench(attr: &ast::Attribute) -> bool { +pub fn is_test_or_bench(attr: &ast::Attribute) -> bool { attr.check_name("test") || attr.check_name("bench") } diff --git a/src/libsyntax/diagnostics/plugin.rs b/src/libsyntax/diagnostics/plugin.rs index 4e50299e83..81c8e0bdb8 100644 --- a/src/libsyntax/diagnostics/plugin.rs +++ b/src/libsyntax/diagnostics/plugin.rs @@ -215,7 +215,7 @@ pub fn expand_build_diagnostic_array<'cx>(ecx: &'cx mut ExtCtxt, let ty = ecx.ty( span, - ast::TyKind::FixedLengthVec( + ast::TyKind::Array( ecx.ty( span, ast::TyKind::Tup(vec![ty_str.clone(), ty_str]) diff --git a/src/libsyntax/ext/base.rs b/src/libsyntax/ext/base.rs index 495ad17654..1f47a91fcc 100644 --- a/src/libsyntax/ext/base.rs +++ b/src/libsyntax/ext/base.rs @@ -15,14 +15,13 @@ use attr::HasAttrs; use codemap::{self, CodeMap, ExpnInfo, Spanned, respan}; use syntax_pos::{Span, ExpnId, NO_EXPANSION}; use errors::DiagnosticBuilder; -use ext::expand::{self, Invocation, Expansion}; +use ext::expand::{self, Expansion}; use ext::hygiene::Mark; use fold::{self, Folder}; use parse::{self, parser}; use parse::token; use parse::token::{InternedString, str_to_ident}; use ptr::P; -use std_inject; use util::small_vector::SmallVector; use std::path::PathBuf; @@ -509,37 +508,47 @@ pub enum SyntaxExtension { /// the block. /// IdentTT(Box, Option, bool), + + CustomDerive(Box), } pub type NamedSyntaxExtension = (Name, SyntaxExtension); pub trait Resolver { fn next_node_id(&mut self) -> ast::NodeId; + fn get_module_scope(&mut self, id: ast::NodeId) -> Mark; fn visit_expansion(&mut self, mark: Mark, expansion: &Expansion); - fn add_macro(&mut self, scope: Mark, def: ast::MacroDef); - fn add_ext(&mut self, scope: Mark, ident: ast::Ident, ext: Rc); + fn add_macro(&mut self, scope: Mark, def: ast::MacroDef, export: bool); + fn add_ext(&mut self, ident: ast::Ident, ext: Rc); fn add_expansions_at_stmt(&mut self, id: ast::NodeId, macros: Vec); fn find_attr_invoc(&mut self, attrs: &mut Vec) -> Option; - fn resolve_invoc(&mut self, scope: Mark, invoc: &Invocation) -> Option>; - fn resolve_derive_mode(&mut self, ident: ast::Ident) -> Option>; + fn resolve_macro(&mut self, scope: Mark, path: &ast::Path, force: bool) + -> Result, Determinacy>; +} + +#[derive(Copy, Clone, Debug)] +pub enum Determinacy { + Determined, + Undetermined, } pub struct DummyResolver; impl Resolver for DummyResolver { fn next_node_id(&mut self) -> ast::NodeId { ast::DUMMY_NODE_ID } + fn get_module_scope(&mut self, _id: ast::NodeId) -> Mark { Mark::root() } fn visit_expansion(&mut self, _invoc: Mark, _expansion: &Expansion) {} - fn add_macro(&mut self, _scope: Mark, _def: ast::MacroDef) {} - fn add_ext(&mut self, _scope: Mark, _ident: ast::Ident, _ext: Rc) {} + fn add_macro(&mut self, _scope: Mark, _def: ast::MacroDef, _export: bool) {} + fn add_ext(&mut self, _ident: ast::Ident, _ext: Rc) {} fn add_expansions_at_stmt(&mut self, _id: ast::NodeId, _macros: Vec) {} fn find_attr_invoc(&mut self, _attrs: &mut Vec) -> Option { None } - fn resolve_derive_mode(&mut self, _ident: ast::Ident) -> Option> { None } - fn resolve_invoc(&mut self, _scope: Mark, _invoc: &Invocation) -> Option> { - None + fn resolve_macro(&mut self, _scope: Mark, _path: &ast::Path, _force: bool) + -> Result, Determinacy> { + Err(Determinacy::Determined) } } @@ -555,7 +564,9 @@ pub struct ExpansionData { pub depth: usize, pub backtrace: ExpnId, pub module: Rc, - pub in_block: bool, + + // True if non-inline modules without a `#[path]` are forbidden at the root of this expansion. + pub no_noninline_mod: bool, } /// One of these is made during expansion and incrementally updated as we go; @@ -563,30 +574,30 @@ pub struct ExpansionData { /// -> expn_info of their expansion context stored into their span. pub struct ExtCtxt<'a> { pub parse_sess: &'a parse::ParseSess, - pub cfg: ast::CrateConfig, pub ecfg: expand::ExpansionConfig<'a>, pub crate_root: Option<&'static str>, pub resolver: &'a mut Resolver, + pub resolve_err_count: usize, pub current_expansion: ExpansionData, } impl<'a> ExtCtxt<'a> { - pub fn new(parse_sess: &'a parse::ParseSess, cfg: ast::CrateConfig, + pub fn new(parse_sess: &'a parse::ParseSess, ecfg: expand::ExpansionConfig<'a>, resolver: &'a mut Resolver) -> ExtCtxt<'a> { ExtCtxt { parse_sess: parse_sess, - cfg: cfg, ecfg: ecfg, crate_root: None, resolver: resolver, + resolve_err_count: 0, current_expansion: ExpansionData { mark: Mark::root(), depth: 0, backtrace: NO_EXPANSION, module: Rc::new(ModuleData { mod_path: Vec::new(), directory: PathBuf::new() }), - in_block: false, + no_noninline_mod: false, }, } } @@ -604,11 +615,13 @@ impl<'a> ExtCtxt<'a> { pub fn new_parser_from_tts(&self, tts: &[tokenstream::TokenTree]) -> parser::Parser<'a> { - parse::tts_to_parser(self.parse_sess, tts.to_vec(), self.cfg()) + let mut parser = parse::tts_to_parser(self.parse_sess, tts.to_vec()); + parser.allow_interpolated_tts = false; // FIXME(jseyfried) `quote!` can't handle these yet + parser } pub fn codemap(&self) -> &'a CodeMap { self.parse_sess.codemap() } pub fn parse_sess(&self) -> &'a parse::ParseSess { self.parse_sess } - pub fn cfg(&self) -> ast::CrateConfig { self.cfg.clone() } + pub fn cfg(&self) -> &ast::CrateConfig { &self.parse_sess.config } pub fn call_site(&self) -> Span { self.codemap().with_expn_info(self.backtrace(), |ei| match ei { Some(expn_info) => expn_info.call_site, @@ -731,28 +744,6 @@ impl<'a> ExtCtxt<'a> { pub fn name_of(&self, st: &str) -> ast::Name { token::intern(st) } - - pub fn initialize(&mut self, user_exts: Vec, krate: &ast::Crate) { - if std_inject::no_core(&krate) { - self.crate_root = None; - } else if std_inject::no_std(&krate) { - self.crate_root = Some("core"); - } else { - self.crate_root = Some("std"); - } - - for (name, extension) in user_exts { - let ident = ast::Ident::with_empty_ctxt(name); - self.resolver.add_ext(Mark::root(), ident, Rc::new(extension)); - } - - let mut module = ModuleData { - mod_path: vec![token::str_to_ident(&self.ecfg.crate_name)], - directory: PathBuf::from(self.parse_sess.codemap().span_to_filename(krate.span)), - }; - module.directory.pop(); - self.current_expansion.module = Rc::new(module); - } } /// Extract a string literal from the macro expanded version of `expr`, diff --git a/src/libsyntax/ext/build.rs b/src/libsyntax/ext/build.rs index b81d95a699..37bd83be7b 100644 --- a/src/libsyntax/ext/build.rs +++ b/src/libsyntax/ext/build.rs @@ -73,6 +73,7 @@ pub trait AstBuilder { fn typaram(&self, span: Span, id: ast::Ident, + attrs: Vec, bounds: ast::TyParamBounds, default: Option>) -> ast::TyParam; @@ -83,6 +84,7 @@ pub trait AstBuilder { fn lifetime_def(&self, span: Span, name: ast::Name, + attrs: Vec, bounds: Vec) -> ast::LifetimeDef; @@ -96,7 +98,7 @@ pub trait AstBuilder { ident: ast::Ident, typ: P, ex: P) - -> P; + -> ast::Stmt; fn stmt_let_type_only(&self, span: Span, ty: P) -> ast::Stmt; fn stmt_item(&self, sp: Span, item: P) -> ast::Stmt; @@ -310,7 +312,7 @@ impl<'a> AstBuilder for ExtCtxt<'a> { self.path_all(span, false, strs, Vec::new(), Vec::new(), Vec::new()) } fn path_ident(&self, span: Span, id: ast::Ident) -> ast::Path { - self.path(span, vec!(id)) + self.path(span, vec![id]) } fn path_global(&self, span: Span, strs: Vec ) -> ast::Path { self.path_all(span, true, strs, Vec::new(), Vec::new(), Vec::new()) @@ -441,7 +443,7 @@ impl<'a> AstBuilder for ExtCtxt<'a> { true, self.std_path(&["option", "Option"]), Vec::new(), - vec!( ty ), + vec![ ty ], Vec::new())) } @@ -452,11 +454,13 @@ impl<'a> AstBuilder for ExtCtxt<'a> { fn typaram(&self, span: Span, id: ast::Ident, + attrs: Vec, bounds: ast::TyParamBounds, default: Option>) -> ast::TyParam { ast::TyParam { ident: id, id: ast::DUMMY_NODE_ID, + attrs: attrs.into(), bounds: bounds, default: default, span: span @@ -473,7 +477,7 @@ impl<'a> AstBuilder for ExtCtxt<'a> { fn ty_vars_global(&self, ty_params: &P<[ast::TyParam]>) -> Vec> { ty_params .iter() - .map(|p| self.ty_path(self.path_global(DUMMY_SP, vec!(p.ident)))) + .map(|p| self.ty_path(self.path_global(DUMMY_SP, vec![p.ident]))) .collect() } @@ -503,9 +507,11 @@ impl<'a> AstBuilder for ExtCtxt<'a> { fn lifetime_def(&self, span: Span, name: ast::Name, + attrs: Vec, bounds: Vec) -> ast::LifetimeDef { ast::LifetimeDef { + attrs: attrs.into(), lifetime: self.lifetime(span, name), bounds: bounds } @@ -556,7 +562,7 @@ impl<'a> AstBuilder for ExtCtxt<'a> { ident: ast::Ident, typ: P, ex: P) - -> P { + -> ast::Stmt { let pat = if mutbl { let binding_mode = ast::BindingMode::ByValue(ast::Mutability::Mutable); self.pat_ident_binding_mode(sp, ident, binding_mode) @@ -571,11 +577,11 @@ impl<'a> AstBuilder for ExtCtxt<'a> { span: sp, attrs: ast::ThinVec::new(), }); - P(ast::Stmt { + ast::Stmt { id: ast::DUMMY_NODE_ID, node: ast::StmtKind::Local(local), span: sp, - }) + } } // Generate `let _: Type;`, usually used for type assertions. @@ -707,7 +713,7 @@ impl<'a> AstBuilder for ExtCtxt<'a> { self.expr(b.span, ast::ExprKind::Block(b)) } fn field_imm(&self, span: Span, name: Ident, e: P) -> ast::Field { - ast::Field { ident: respan(span, name), expr: e, span: span } + ast::Field { ident: respan(span, name), expr: e, span: span, is_shorthand: false } } fn expr_struct(&self, span: Span, path: ast::Path, fields: Vec) -> P { self.expr(span, ast::ExprKind::Struct(path, fields, None)) @@ -764,7 +770,7 @@ impl<'a> AstBuilder for ExtCtxt<'a> { fn expr_some(&self, sp: Span, expr: P) -> P { let some = self.std_path(&["option", "Option", "Some"]); - self.expr_call_global(sp, some, vec!(expr)) + self.expr_call_global(sp, some, vec![expr]) } fn expr_none(&self, sp: Span) -> P { @@ -788,14 +794,14 @@ impl<'a> AstBuilder for ExtCtxt<'a> { let expr_file = self.expr_str(span, token::intern_and_get_ident(&loc.file.name)); 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_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( span, self.std_path(&["rt", "begin_panic"]), - vec!( + vec![ self.expr_str(span, msg), - expr_file_line_ptr)) + expr_file_line_ptr]) } fn expr_unreachable(&self, span: Span) -> P { @@ -806,12 +812,12 @@ impl<'a> AstBuilder for ExtCtxt<'a> { fn expr_ok(&self, sp: Span, expr: P) -> P { let ok = self.std_path(&["result", "Result", "Ok"]); - self.expr_call_global(sp, ok, vec!(expr)) + self.expr_call_global(sp, ok, vec![expr]) } fn expr_err(&self, sp: Span, expr: P) -> P { let err = self.std_path(&["result", "Result", "Err"]); - self.expr_call_global(sp, err, vec!(expr)) + self.expr_call_global(sp, err, vec![expr]) } fn expr_try(&self, sp: Span, head: P) -> P { @@ -830,17 +836,17 @@ impl<'a> AstBuilder for ExtCtxt<'a> { // Err(__try_var) (pattern and expression resp.) let err_pat = self.pat_tuple_struct(sp, err_path.clone(), vec![binding_pat]); let err_inner_expr = self.expr_call(sp, self.expr_path(err_path), - vec!(binding_expr.clone())); + vec![binding_expr.clone()]); // return Err(__try_var) let err_expr = self.expr(sp, ast::ExprKind::Ret(Some(err_inner_expr))); // Ok(__try_var) => __try_var - let ok_arm = self.arm(sp, vec!(ok_pat), binding_expr); + let ok_arm = self.arm(sp, vec![ok_pat], binding_expr); // Err(__try_var) => return Err(__try_var) - let err_arm = self.arm(sp, vec!(err_pat), err_expr); + let err_arm = self.arm(sp, vec![err_pat], err_expr); // match head { Ok() => ..., Err() => ... } - self.expr_match(sp, head, vec!(ok_arm, err_arm)) + self.expr_match(sp, head, vec![ok_arm, err_arm]) } @@ -906,7 +912,7 @@ impl<'a> AstBuilder for ExtCtxt<'a> { fn arm(&self, _span: Span, pats: Vec>, expr: P) -> ast::Arm { ast::Arm { - attrs: vec!(), + attrs: vec![], pats: pats, guard: None, body: expr @@ -914,7 +920,7 @@ impl<'a> AstBuilder for ExtCtxt<'a> { } fn arm_unreachable(&self, span: Span) -> ast::Arm { - self.arm(span, vec!(self.pat_wild(span)), self.expr_unreachable(span)) + self.arm(span, vec![self.pat_wild(span)], self.expr_unreachable(span)) } fn expr_match(&self, span: Span, arg: P, arms: Vec) -> P { @@ -964,7 +970,7 @@ impl<'a> AstBuilder for ExtCtxt<'a> { } fn lambda1(&self, span: Span, blk: P, ident: ast::Ident) -> P { - self.lambda(span, vec!(ident), blk) + self.lambda(span, vec![ident], blk) } fn lambda_expr(&self, span: Span, ids: Vec, diff --git a/src/libsyntax/ext/expand.rs b/src/libsyntax/ext/expand.rs index 8436835da3..e3b23e239f 100644 --- a/src/libsyntax/ext/expand.rs +++ b/src/libsyntax/ext/expand.rs @@ -8,7 +8,7 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -use ast::{Block, Crate, Ident, Mac_, PatKind}; +use ast::{Block, Ident, Mac_, PatKind}; use ast::{Name, MacStmtStyle, StmtKind, ItemKind}; use ast; use ext::hygiene::Mark; @@ -16,7 +16,7 @@ use ext::placeholders::{placeholder, PlaceholderExpander}; use attr::{self, HasAttrs}; use codemap::{ExpnInfo, NameAndSpan, MacroBang, MacroAttribute}; use syntax_pos::{self, Span, ExpnId}; -use config::StripUnconfigured; +use config::{is_test_or_bench, StripUnconfigured}; use ext::base::*; use feature_gate::{self, Features}; use fold; @@ -26,6 +26,7 @@ use parse::parser::Parser; use parse::token::{self, intern, keywords}; use print::pprust; use ptr::P; +use std_inject; use tokenstream::{TokenTree, TokenStream}; use util::small_vector::SmallVector; use visit::Visitor; @@ -186,8 +187,14 @@ impl<'a, 'b> MacroExpander<'a, 'b> { MacroExpander { cx: cx, monotonic: monotonic } } - fn expand_crate(&mut self, mut krate: ast::Crate) -> ast::Crate { - let err_count = self.cx.parse_sess.span_diagnostic.err_count(); + pub fn expand_crate(&mut self, mut krate: ast::Crate) -> ast::Crate { + self.cx.crate_root = std_inject::injected_crate_name(&krate); + let mut module = ModuleData { + mod_path: vec![token::str_to_ident(&self.cx.ecfg.crate_name)], + directory: PathBuf::from(self.cx.codemap().span_to_filename(krate.span)), + }; + module.directory.pop(); + self.cx.current_expansion.module = Rc::new(module); let krate_item = Expansion::Items(SmallVector::one(P(ast::Item { attrs: krate.attrs, @@ -206,10 +213,6 @@ impl<'a, 'b> MacroExpander<'a, 'b> { _ => unreachable!(), }; - if self.cx.parse_sess.span_diagnostic.err_count() > err_count { - self.cx.parse_sess.span_diagnostic.abort_if_errors(); - } - krate } @@ -221,25 +224,57 @@ impl<'a, 'b> MacroExpander<'a, 'b> { let (expansion, mut invocations) = self.collect_invocations(expansion); invocations.reverse(); - let mut expansions = vec![vec![(0, expansion)]]; - while let Some(invoc) = invocations.pop() { + let mut expansions = Vec::new(); + let mut undetermined_invocations = Vec::new(); + let (mut progress, mut force) = (false, !self.monotonic); + loop { + let invoc = if let Some(invoc) = invocations.pop() { + invoc + } else if undetermined_invocations.is_empty() { + break + } else { + invocations = mem::replace(&mut undetermined_invocations, Vec::new()); + force = !mem::replace(&mut progress, false); + continue + }; + + let scope = + if self.monotonic { invoc.expansion_data.mark } else { orig_expansion_data.mark }; + let resolution = match invoc.kind { + InvocationKind::Bang { ref mac, .. } => { + self.cx.resolver.resolve_macro(scope, &mac.node.path, force) + } + InvocationKind::Attr { ref attr, .. } => { + let ident = ast::Ident::with_empty_ctxt(intern(&*attr.name())); + let path = ast::Path::from_ident(attr.span, ident); + self.cx.resolver.resolve_macro(scope, &path, force) + } + }; + let ext = match resolution { + Ok(ext) => Some(ext), + Err(Determinacy::Determined) => None, + Err(Determinacy::Undetermined) => { + undetermined_invocations.push(invoc); + continue + } + }; + + progress = true; let ExpansionData { depth, mark, .. } = invoc.expansion_data; self.cx.current_expansion = invoc.expansion_data.clone(); - let scope = if self.monotonic { mark } else { orig_expansion_data.mark }; self.cx.current_expansion.mark = scope; - let expansion = match self.cx.resolver.resolve_invoc(scope, &invoc) { + let expansion = match ext { Some(ext) => self.expand_invoc(invoc, ext), None => invoc.expansion_kind.dummy(invoc.span()), }; - self.cx.current_expansion.depth = depth + 1; let (expansion, new_invocations) = self.collect_invocations(expansion); - if expansions.len() == depth { + if expansions.len() < depth { expansions.push(Vec::new()); } - expansions[depth].push((mark.as_u32(), expansion)); + expansions[depth - 1].push((mark.as_u32(), expansion)); if !self.cx.ecfg.single_step { invocations.extend(new_invocations.into_iter().rev()); } @@ -250,20 +285,17 @@ impl<'a, 'b> MacroExpander<'a, 'b> { let mut placeholder_expander = PlaceholderExpander::new(self.cx, self.monotonic); while let Some(expansions) = expansions.pop() { for (mark, expansion) in expansions.into_iter().rev() { - let expansion = expansion.fold_with(&mut placeholder_expander); placeholder_expander.add(ast::NodeId::from_u32(mark), expansion); } } - placeholder_expander.remove(ast::NodeId::from_u32(0)) + expansion.fold_with(&mut placeholder_expander) } fn collect_invocations(&mut self, expansion: Expansion) -> (Expansion, Vec) { - let crate_config = mem::replace(&mut self.cx.cfg, Vec::new()); let result = { let mut collector = InvocationCollector { cfg: StripUnconfigured { - config: &crate_config, should_test: self.cx.ecfg.should_test, sess: self.cx.parse_sess, features: self.cx.ecfg.features, @@ -274,11 +306,12 @@ impl<'a, 'b> MacroExpander<'a, 'b> { }; (expansion.fold_with(&mut collector), collector.invocations) }; - self.cx.cfg = crate_config; if self.monotonic { + let err_count = self.cx.parse_sess.span_diagnostic.err_count(); let mark = self.cx.current_expansion.mark; self.cx.resolver.visit_expansion(mark, &result.0); + self.cx.resolve_err_count += self.cx.parse_sess.span_diagnostic.err_count() - err_count; } result @@ -328,7 +361,15 @@ impl<'a, 'b> MacroExpander<'a, 'b> { let tok_result = mac.expand(self.cx, attr.span, attr_toks, item_toks); self.parse_expansion(tok_result, kind, name, attr.span) } - _ => unreachable!(), + SyntaxExtension::CustomDerive(_) => { + self.cx.span_err(attr.span, &format!("`{}` is a derive mode", name)); + kind.dummy(attr.span) + } + _ => { + let msg = &format!("macro `{}` may not be used in attributes", name); + self.cx.span_err(attr.span, &msg); + kind.dummy(attr.span) + } } } @@ -403,6 +444,11 @@ impl<'a, 'b> MacroExpander<'a, 'b> { return kind.dummy(span); } + SyntaxExtension::CustomDerive(..) => { + self.cx.span_err(path.span, &format!("`{}` is a derive mode", extname)); + return kind.dummy(span); + } + SyntaxExtension::ProcMacro(ref expandfun) => { if ident.name != keywords::Invalid.name() { let msg = @@ -536,7 +582,11 @@ impl<'a, 'b> InvocationCollector<'a, 'b> { self.invocations.push(Invocation { kind: kind, expansion_kind: expansion_kind, - expansion_data: ExpansionData { mark: mark, ..self.cx.current_expansion.clone() }, + expansion_data: ExpansionData { + mark: mark, + depth: self.cx.current_expansion.depth + 1, + ..self.cx.current_expansion.clone() + }, }); placeholder(expansion_kind, ast::NodeId::from_u32(mark.as_u32())) } @@ -593,7 +643,7 @@ fn string_to_tts(text: String, parse_sess: &ParseSess) -> Vec { .new_filemap(String::from(""), None, text); let lexer = lexer::StringReader::new(&parse_sess.span_diagnostic, filemap); - let mut parser = Parser::new(parse_sess, Vec::new(), Box::new(lexer)); + let mut parser = Parser::new(parse_sess, Box::new(lexer)); panictry!(parser.parse_all_token_trees()) } @@ -665,16 +715,16 @@ impl<'a, 'b> Folder for InvocationCollector<'a, 'b> { } fn fold_block(&mut self, block: P) -> P { - let orig_in_block = mem::replace(&mut self.cx.current_expansion.in_block, true); + let no_noninline_mod = mem::replace(&mut self.cx.current_expansion.no_noninline_mod, true); let result = noop_fold_block(block, self); - self.cx.current_expansion.in_block = orig_in_block; + self.cx.current_expansion.no_noninline_mod = no_noninline_mod; result } fn fold_item(&mut self, item: P) -> SmallVector> { let item = configure!(self, item); - let (item, attr) = self.classify_item(item); + let (mut item, attr) = self.classify_item(item); if let Some(attr) = attr { let item = Annotatable::Item(fully_configure!(self, item, noop_fold_item)); return self.collect_attr(attr, item, ExpansionKind::Items).make_items(); @@ -706,6 +756,7 @@ impl<'a, 'b> Folder for InvocationCollector<'a, 'b> { return noop_fold_item(item, self); } + let orig_no_noninline_mod = self.cx.current_expansion.no_noninline_mod; let mut module = (*self.cx.current_expansion.module).clone(); module.mod_path.push(item.ident); @@ -715,11 +766,14 @@ impl<'a, 'b> Folder for InvocationCollector<'a, 'b> { let inline_module = item.span.contains(inner) || inner == syntax_pos::DUMMY_SP; if inline_module { - module.directory.push(&*{ - ::attr::first_attr_value_str_by_name(&item.attrs, "path") - .unwrap_or(item.ident.name.as_str()) - }); + if let Some(path) = attr::first_attr_value_str_by_name(&item.attrs, "path") { + self.cx.current_expansion.no_noninline_mod = false; + module.directory.push(&*path); + } else { + module.directory.push(&*item.ident.name.as_str()); + } } else { + self.cx.current_expansion.no_noninline_mod = false; module.directory = PathBuf::from(self.cx.parse_sess.codemap().span_to_filename(inner)); module.directory.pop(); @@ -729,8 +783,16 @@ impl<'a, 'b> Folder for InvocationCollector<'a, 'b> { mem::replace(&mut self.cx.current_expansion.module, Rc::new(module)); let result = noop_fold_item(item, self); self.cx.current_expansion.module = orig_module; + self.cx.current_expansion.no_noninline_mod = orig_no_noninline_mod; return result; } + // Ensure that test functions are accessible from the test harness. + ast::ItemKind::Fn(..) if self.cx.ecfg.should_test => { + if item.attrs.iter().any(|attr| is_test_or_bench(attr)) { + item = item.map(|mut item| { item.vis = ast::Visibility::Public; item }); + } + noop_fold_item(item, self) + } _ => noop_fold_item(item, self), } } @@ -848,26 +910,10 @@ impl<'feat> ExpansionConfig<'feat> { fn enable_allow_internal_unstable = allow_internal_unstable, fn enable_custom_derive = custom_derive, fn enable_pushpop_unsafe = pushpop_unsafe, - fn enable_rustc_macro = rustc_macro, + fn enable_proc_macro = proc_macro, } } -pub fn expand_crate(cx: &mut ExtCtxt, - user_exts: Vec, - c: Crate) -> Crate { - cx.initialize(user_exts, &c); - cx.monotonic_expander().expand_crate(c) -} - -// Expands crate using supplied MacroExpander - allows for -// non-standard expansion behaviour (e.g. step-wise). -pub fn expand_crate_with_expander(expander: &mut MacroExpander, - user_exts: Vec, - c: Crate) -> Crate { - expander.cx.initialize(user_exts, &c); - expander.expand_crate(c) -} - // A Marker adds the given mark to the syntax context and // sets spans' `expn_id` to the given expn_id (unless it is `None`). struct Marker { mark: Mark, expn_id: Option } @@ -890,6 +936,6 @@ impl Folder for Marker { } // apply a given mark to the given token trees. Used prior to expansion of a macro. -fn mark_tts(tts: &[TokenTree], m: Mark) -> Vec { +pub fn mark_tts(tts: &[TokenTree], m: Mark) -> Vec { noop_fold_tts(tts, &mut Marker{mark:m, expn_id: None}) } diff --git a/src/libsyntax/ext/hygiene.rs b/src/libsyntax/ext/hygiene.rs index 34126fac4a..0fd72277cc 100644 --- a/src/libsyntax/ext/hygiene.rs +++ b/src/libsyntax/ext/hygiene.rs @@ -15,6 +15,7 @@ //! and definition contexts*. J. Funct. Program. 22, 2 (March 2012), 181-216. //! DOI=10.1017/S0956796812000093 http://dx.doi.org/10.1017/S0956796812000093 +use ast::NodeId; use std::cell::RefCell; use std::collections::HashMap; use std::fmt; @@ -46,6 +47,10 @@ impl Mark { Mark(0) } + pub fn from_placeholder_id(id: NodeId) -> Self { + Mark(id.as_u32()) + } + pub fn as_u32(&self) -> u32 { self.0 } diff --git a/src/libsyntax/ext/placeholders.rs b/src/libsyntax/ext/placeholders.rs index 0ede6dd98e..e323dd2f62 100644 --- a/src/libsyntax/ext/placeholders.rs +++ b/src/libsyntax/ext/placeholders.rs @@ -88,10 +88,11 @@ impl<'a, 'b> PlaceholderExpander<'a, 'b> { } pub fn add(&mut self, id: ast::NodeId, expansion: Expansion) { + let expansion = expansion.fold_with(self); self.expansions.insert(id, expansion); } - pub fn remove(&mut self, id: ast::NodeId) -> Expansion { + fn remove(&mut self, id: ast::NodeId) -> Expansion { self.expansions.remove(&id).unwrap() } } diff --git a/src/libsyntax/ext/quote.rs b/src/libsyntax/ext/quote.rs index b70e270df5..969cfa292c 100644 --- a/src/libsyntax/ext/quote.rs +++ b/src/libsyntax/ext/quote.rs @@ -46,7 +46,7 @@ pub mod rt { impl ToTokens for TokenTree { fn to_tokens(&self, _cx: &ExtCtxt) -> Vec { - vec!(self.clone()) + vec![self.clone()] } } @@ -80,67 +80,71 @@ pub mod rt { impl ToTokens for ast::Path { fn to_tokens(&self, _cx: &ExtCtxt) -> Vec { - vec![TokenTree::Token(DUMMY_SP, - token::Interpolated(token::NtPath(Box::new(self.clone()))))] + let nt = token::NtPath(self.clone()); + vec![TokenTree::Token(DUMMY_SP, token::Interpolated(Rc::new(nt)))] } } impl ToTokens for ast::Ty { fn to_tokens(&self, _cx: &ExtCtxt) -> Vec { - vec![TokenTree::Token(self.span, token::Interpolated(token::NtTy(P(self.clone()))))] + let nt = token::NtTy(P(self.clone())); + vec![TokenTree::Token(self.span, token::Interpolated(Rc::new(nt)))] } } impl ToTokens for ast::Block { fn to_tokens(&self, _cx: &ExtCtxt) -> Vec { - vec![TokenTree::Token(self.span, token::Interpolated(token::NtBlock(P(self.clone()))))] + let nt = token::NtBlock(P(self.clone())); + vec![TokenTree::Token(self.span, token::Interpolated(Rc::new(nt)))] } } impl ToTokens for ast::Generics { fn to_tokens(&self, _cx: &ExtCtxt) -> Vec { - vec![TokenTree::Token(DUMMY_SP, token::Interpolated(token::NtGenerics(self.clone())))] + let nt = token::NtGenerics(self.clone()); + vec![TokenTree::Token(DUMMY_SP, token::Interpolated(Rc::new(nt)))] } } impl ToTokens for ast::WhereClause { fn to_tokens(&self, _cx: &ExtCtxt) -> Vec { - vec![TokenTree::Token(DUMMY_SP, - token::Interpolated(token::NtWhereClause(self.clone())))] + let nt = token::NtWhereClause(self.clone()); + vec![TokenTree::Token(DUMMY_SP, token::Interpolated(Rc::new(nt)))] } } impl ToTokens for P { fn to_tokens(&self, _cx: &ExtCtxt) -> Vec { - vec![TokenTree::Token(self.span, token::Interpolated(token::NtItem(self.clone())))] + let nt = token::NtItem(self.clone()); + vec![TokenTree::Token(self.span, token::Interpolated(Rc::new(nt)))] } } impl ToTokens for ast::ImplItem { fn to_tokens(&self, _cx: &ExtCtxt) -> Vec { - vec![TokenTree::Token(self.span, - token::Interpolated(token::NtImplItem(P(self.clone()))))] + let nt = token::NtImplItem(self.clone()); + vec![TokenTree::Token(self.span, token::Interpolated(Rc::new(nt)))] } } impl ToTokens for P { fn to_tokens(&self, _cx: &ExtCtxt) -> Vec { - vec![TokenTree::Token(self.span, token::Interpolated(token::NtImplItem(self.clone())))] + let nt = token::NtImplItem((**self).clone()); + vec![TokenTree::Token(self.span, token::Interpolated(Rc::new(nt)))] } } impl ToTokens for ast::TraitItem { fn to_tokens(&self, _cx: &ExtCtxt) -> Vec { - vec![TokenTree::Token(self.span, - token::Interpolated(token::NtTraitItem(P(self.clone()))))] + let nt = token::NtTraitItem(self.clone()); + vec![TokenTree::Token(self.span, token::Interpolated(Rc::new(nt)))] } } impl ToTokens for ast::Stmt { fn to_tokens(&self, _cx: &ExtCtxt) -> Vec { - let mut tts = vec![ - TokenTree::Token(self.span, token::Interpolated(token::NtStmt(P(self.clone())))) - ]; + let nt = token::NtStmt(self.clone()); + let mut tts = vec![TokenTree::Token(self.span, token::Interpolated(Rc::new(nt)))]; // Some statements require a trailing semicolon. if classify::stmt_ends_with_semi(&self.node) { @@ -153,31 +157,36 @@ pub mod rt { impl ToTokens for P { fn to_tokens(&self, _cx: &ExtCtxt) -> Vec { - vec![TokenTree::Token(self.span, token::Interpolated(token::NtExpr(self.clone())))] + let nt = token::NtExpr(self.clone()); + vec![TokenTree::Token(self.span, token::Interpolated(Rc::new(nt)))] } } impl ToTokens for P { fn to_tokens(&self, _cx: &ExtCtxt) -> Vec { - vec![TokenTree::Token(self.span, token::Interpolated(token::NtPat(self.clone())))] + let nt = token::NtPat(self.clone()); + vec![TokenTree::Token(self.span, token::Interpolated(Rc::new(nt)))] } } impl ToTokens for ast::Arm { fn to_tokens(&self, _cx: &ExtCtxt) -> Vec { - vec![TokenTree::Token(DUMMY_SP, token::Interpolated(token::NtArm(self.clone())))] + let nt = token::NtArm(self.clone()); + vec![TokenTree::Token(DUMMY_SP, token::Interpolated(Rc::new(nt)))] } } impl ToTokens for ast::Arg { fn to_tokens(&self, _cx: &ExtCtxt) -> Vec { - vec![TokenTree::Token(DUMMY_SP, token::Interpolated(token::NtArg(self.clone())))] + let nt = token::NtArg(self.clone()); + vec![TokenTree::Token(DUMMY_SP, token::Interpolated(Rc::new(nt)))] } } impl ToTokens for P { fn to_tokens(&self, _cx: &ExtCtxt) -> Vec { - vec![TokenTree::Token(DUMMY_SP, token::Interpolated(token::NtBlock(self.clone())))] + let nt = token::NtBlock(self.clone()); + vec![TokenTree::Token(DUMMY_SP, token::Interpolated(Rc::new(nt)))] } } @@ -204,7 +213,8 @@ pub mod rt { impl ToTokens for P { fn to_tokens(&self, _cx: &ExtCtxt) -> Vec { - vec![TokenTree::Token(DUMMY_SP, token::Interpolated(token::NtMeta(self.clone())))] + let nt = token::NtMeta(self.clone()); + vec![TokenTree::Token(DUMMY_SP, token::Interpolated(Rc::new(nt)))] } } @@ -331,7 +341,6 @@ pub mod rt { panictry!(parse::parse_item_from_source_str( "".to_string(), s, - self.cfg(), self.parse_sess())).expect("parse error") } @@ -339,7 +348,6 @@ pub mod rt { panictry!(parse::parse_stmt_from_source_str( "".to_string(), s, - self.cfg(), self.parse_sess())).expect("parse error") } @@ -347,7 +355,6 @@ pub mod rt { panictry!(parse::parse_expr_from_source_str( "".to_string(), s, - self.cfg(), self.parse_sess())) } @@ -355,7 +362,6 @@ pub mod rt { panictry!(parse::parse_tts_from_source_str( "".to_string(), s, - self.cfg(), self.parse_sess())) } } @@ -420,7 +426,7 @@ pub fn expand_quote_expr<'cx>(cx: &'cx mut ExtCtxt, sp: Span, tts: &[TokenTree]) -> Box { - let expanded = expand_parse_call(cx, sp, "parse_expr_panic", vec!(), tts); + let expanded = expand_parse_call(cx, sp, "parse_expr_panic", vec![], tts); base::MacEager::expr(expanded) } @@ -428,7 +434,7 @@ pub fn expand_quote_item<'cx>(cx: &'cx mut ExtCtxt, sp: Span, tts: &[TokenTree]) -> Box { - let expanded = expand_parse_call(cx, sp, "parse_item_panic", vec!(), tts); + let expanded = expand_parse_call(cx, sp, "parse_item_panic", vec![], tts); base::MacEager::expr(expanded) } @@ -436,7 +442,7 @@ pub fn expand_quote_pat<'cx>(cx: &'cx mut ExtCtxt, sp: Span, tts: &[TokenTree]) -> Box { - let expanded = expand_parse_call(cx, sp, "parse_pat_panic", vec!(), tts); + let expanded = expand_parse_call(cx, sp, "parse_pat_panic", vec![], tts); base::MacEager::expr(expanded) } @@ -444,7 +450,7 @@ pub fn expand_quote_arm(cx: &mut ExtCtxt, sp: Span, tts: &[TokenTree]) -> Box { - let expanded = expand_parse_call(cx, sp, "parse_arm_panic", vec!(), tts); + let expanded = expand_parse_call(cx, sp, "parse_arm_panic", vec![], tts); base::MacEager::expr(expanded) } @@ -452,7 +458,7 @@ pub fn expand_quote_ty(cx: &mut ExtCtxt, sp: Span, tts: &[TokenTree]) -> Box { - let expanded = expand_parse_call(cx, sp, "parse_ty_panic", vec!(), tts); + let expanded = expand_parse_call(cx, sp, "parse_ty_panic", vec![], tts); base::MacEager::expr(expanded) } @@ -460,7 +466,7 @@ pub fn expand_quote_stmt(cx: &mut ExtCtxt, sp: Span, tts: &[TokenTree]) -> Box { - let expanded = expand_parse_call(cx, sp, "parse_stmt_panic", vec!(), tts); + let expanded = expand_parse_call(cx, sp, "parse_stmt_panic", vec![], tts); base::MacEager::expr(expanded) } @@ -469,7 +475,7 @@ pub fn expand_quote_attr(cx: &mut ExtCtxt, tts: &[TokenTree]) -> Box { let expanded = expand_parse_call(cx, sp, "parse_attribute_panic", - vec!(cx.expr_bool(sp, true)), tts); + vec![cx.expr_bool(sp, true)], tts); base::MacEager::expr(expanded) } @@ -478,7 +484,7 @@ pub fn expand_quote_arg(cx: &mut ExtCtxt, sp: Span, tts: &[TokenTree]) -> Box { - let expanded = expand_parse_call(cx, sp, "parse_arg_panic", vec!(), tts); + let expanded = expand_parse_call(cx, sp, "parse_arg_panic", vec![], tts); base::MacEager::expr(expanded) } @@ -486,7 +492,7 @@ pub fn expand_quote_block(cx: &mut ExtCtxt, sp: Span, tts: &[TokenTree]) -> Box { - let expanded = expand_parse_call(cx, sp, "parse_block_panic", vec!(), tts); + let expanded = expand_parse_call(cx, sp, "parse_block_panic", vec![], tts); base::MacEager::expr(expanded) } @@ -494,7 +500,7 @@ pub fn expand_quote_meta_item(cx: &mut ExtCtxt, sp: Span, tts: &[TokenTree]) -> Box { - let expanded = expand_parse_call(cx, sp, "parse_meta_item_panic", vec!(), tts); + let expanded = expand_parse_call(cx, sp, "parse_meta_item_panic", vec![], tts); base::MacEager::expr(expanded) } @@ -503,7 +509,7 @@ pub fn expand_quote_path(cx: &mut ExtCtxt, tts: &[TokenTree]) -> Box { let mode = mk_parser_path(cx, sp, &["PathStyle", "Type"]); - let expanded = expand_parse_call(cx, sp, "parse_path_panic", vec!(mode), tts); + let expanded = expand_parse_call(cx, sp, "parse_path_panic", vec![mode], tts); base::MacEager::expr(expanded) } @@ -535,7 +541,7 @@ fn mk_ident(cx: &ExtCtxt, sp: Span, ident: ast::Ident) -> P { cx.expr_method_call(sp, cx.expr_ident(sp, id_ext("ext_cx")), id_ext("ident_of"), - vec!(e_str)) + vec![e_str]) } // Lift a name to the expr that evaluates to that name @@ -544,16 +550,16 @@ fn mk_name(cx: &ExtCtxt, sp: Span, ident: ast::Ident) -> P { cx.expr_method_call(sp, cx.expr_ident(sp, id_ext("ext_cx")), id_ext("name_of"), - vec!(e_str)) + vec![e_str]) } fn mk_tt_path(cx: &ExtCtxt, sp: Span, name: &str) -> P { - let idents = vec!(id_ext("syntax"), id_ext("tokenstream"), id_ext("TokenTree"), id_ext(name)); + let idents = vec![id_ext("syntax"), id_ext("tokenstream"), id_ext("TokenTree"), id_ext(name)]; cx.expr_path(cx.path_global(sp, idents)) } fn mk_token_path(cx: &ExtCtxt, sp: Span, name: &str) -> P { - let idents = vec!(id_ext("syntax"), id_ext("parse"), id_ext("token"), id_ext(name)); + let idents = vec![id_ext("syntax"), id_ext("parse"), id_ext("token"), id_ext(name)]; cx.expr_path(cx.path_global(sp, idents)) } @@ -603,11 +609,11 @@ fn expr_mk_token(cx: &ExtCtxt, sp: Span, tok: &token::Token) -> P { } match *tok { token::BinOp(binop) => { - return cx.expr_call(sp, mk_token_path(cx, sp, "BinOp"), vec!(mk_binop(cx, sp, binop))); + return cx.expr_call(sp, mk_token_path(cx, sp, "BinOp"), vec![mk_binop(cx, sp, binop)]); } token::BinOpEq(binop) => { return cx.expr_call(sp, mk_token_path(cx, sp, "BinOpEq"), - vec!(mk_binop(cx, sp, binop))); + vec![mk_binop(cx, sp, binop)]); } token::OpenDelim(delim) => { @@ -657,13 +663,13 @@ fn expr_mk_token(cx: &ExtCtxt, sp: Span, tok: &token::Token) -> P { token::Lifetime(ident) => { return cx.expr_call(sp, mk_token_path(cx, sp, "Lifetime"), - vec!(mk_ident(cx, sp, ident))); + vec![mk_ident(cx, sp, ident)]); } token::DocComment(ident) => { return cx.expr_call(sp, mk_token_path(cx, sp, "DocComment"), - vec!(mk_name(cx, sp, ast::Ident::with_empty_ctxt(ident)))); + vec![mk_name(cx, sp, ast::Ident::with_empty_ctxt(ident))]); } token::MatchNt(name, kind) => { @@ -718,7 +724,7 @@ fn statements_mk_tt(cx: &ExtCtxt, tt: &TokenTree, matcher: bool) -> Vec Vec { let mut seq = vec![]; @@ -741,13 +747,13 @@ fn statements_mk_tt(cx: &ExtCtxt, tt: &TokenTree, matcher: bool) -> Vec { statements_mk_tt(cx, &delimed.open_tt(), matcher).into_iter() @@ -800,13 +806,13 @@ fn statements_mk_tt(cx: &ExtCtxt, tt: &TokenTree, matcher: bool) -> Vec Vec { let stmt_let_tt = cx.stmt_let(sp, true, id_ext("tt"), cx.expr_vec_ng(sp)); - vec!(stmt_let_sp, stmt_let_tt) + vec![stmt_let_sp, stmt_let_tt] } fn statements_mk_tts(cx: &ExtCtxt, tts: &[TokenTree], matcher: bool) -> Vec { @@ -920,10 +926,6 @@ fn expand_parse_call(cx: &ExtCtxt, tts: &[TokenTree]) -> P { let (cx_expr, tts_expr) = expand_tts(cx, sp, tts); - let cfg_call = || cx.expr_method_call( - sp, cx.expr_ident(sp, id_ext("ext_cx")), - id_ext("cfg"), Vec::new()); - let parse_sess_call = || cx.expr_method_call( sp, cx.expr_ident(sp, id_ext("ext_cx")), id_ext("parse_sess"), Vec::new()); @@ -931,7 +933,7 @@ fn expand_parse_call(cx: &ExtCtxt, let new_parser_call = cx.expr_call(sp, cx.expr_ident(sp, id_ext("new_parser_from_tts")), - vec!(parse_sess_call(), cfg_call(), tts_expr)); + vec![parse_sess_call(), tts_expr]); let path = vec![id_ext("syntax"), id_ext("ext"), id_ext("quote"), id_ext(parse_method)]; let mut args = vec![cx.expr_mut_addr_of(sp, new_parser_call)]; diff --git a/src/libsyntax/ext/source_util.rs b/src/libsyntax/ext/source_util.rs index e75e41d0c2..ec48cae3f7 100644 --- a/src/libsyntax/ext/source_util.rs +++ b/src/libsyntax/ext/source_util.rs @@ -92,15 +92,8 @@ pub fn expand_include<'cx>(cx: &'cx mut ExtCtxt, sp: Span, tts: &[tokenstream::T None => return DummyResult::expr(sp), }; // The file will be added to the code map by the parser - let p = - parse::new_sub_parser_from_file(cx.parse_sess(), - cx.cfg(), - &res_rel_file(cx, - sp, - Path::new(&file)), - true, - None, - sp); + let path = res_rel_file(cx, sp, Path::new(&file)); + let p = parse::new_sub_parser_from_file(cx.parse_sess(), &path, true, None, sp); struct ExpandResult<'a> { p: parse::parser::Parser<'a>, diff --git a/src/libsyntax/ext/tt/macro_parser.rs b/src/libsyntax/ext/tt/macro_parser.rs index b0696a986e..1066646aa8 100644 --- a/src/libsyntax/ext/tt/macro_parser.rs +++ b/src/libsyntax/ext/tt/macro_parser.rs @@ -78,7 +78,6 @@ pub use self::NamedMatch::*; pub use self::ParseResult::*; use self::TokenTreeOrTokenTreeVec::*; -use ast; use ast::Ident; use syntax_pos::{self, BytePos, mk_sp, Span}; use codemap::Spanned; @@ -90,8 +89,8 @@ use parse::token::{DocComment, MatchNt, SubstNt}; use parse::token::{Token, Nonterminal}; use parse::token; use print::pprust; -use ptr::P; use tokenstream::{self, TokenTree}; +use util::small_vector::SmallVector; use std::mem; use std::rc::Rc; @@ -104,7 +103,7 @@ use std::collections::hash_map::Entry::{Vacant, Occupied}; #[derive(Clone)] enum TokenTreeOrTokenTreeVec { Tt(tokenstream::TokenTree), - TtSeq(Rc>), + TtSeq(Vec), } impl TokenTreeOrTokenTreeVec { @@ -161,7 +160,7 @@ pub fn count_names(ms: &[TokenTree]) -> usize { }) } -pub fn initial_matcher_pos(ms: Rc>, sep: Option, lo: BytePos) +pub fn initial_matcher_pos(ms: Vec, sep: Option, lo: BytePos) -> Box { let match_idx_hi = count_names(&ms[..]); let matches: Vec<_> = (0..match_idx_hi).map(|_| Vec::new()).collect(); @@ -198,7 +197,7 @@ pub fn initial_matcher_pos(ms: Rc>, sep: Option, lo: ByteP pub enum NamedMatch { MatchedSeq(Vec>, syntax_pos::Span), - MatchedNonterminal(Nonterminal) + MatchedNonterminal(Rc) } pub fn nameize(p_s: &ParseSess, ms: &[TokenTree], res: &[Rc]) @@ -251,14 +250,22 @@ pub fn nameize(p_s: &ParseSess, ms: &[TokenTree], res: &[Rc]) pub enum ParseResult { Success(T), - /// Arm failed to match - Failure(syntax_pos::Span, String), + /// Arm failed to match. If the second parameter is `token::Eof`, it + /// indicates an unexpected end of macro invocation. Otherwise, it + /// indicates that no rules expected the given token. + Failure(syntax_pos::Span, Token), /// Fatal error (malformed macro?). Abort compilation. Error(syntax_pos::Span, String) } +pub fn parse_failure_msg(tok: Token) -> String { + match tok { + token::Eof => "unexpected end of macro invocation".to_string(), + _ => format!("no rules expected the token `{}`", pprust::token_to_string(&tok)), + } +} + pub type NamedParseResult = ParseResult>>; -pub type PositionalParseResult = ParseResult>>; /// Perform a token equality check, ignoring syntax context (that is, an /// unhygienic comparison) @@ -271,24 +278,16 @@ pub fn token_name_eq(t1 : &Token, t2 : &Token) -> bool { } } -pub fn parse(sess: &ParseSess, - cfg: ast::CrateConfig, - mut rdr: TtReader, - ms: &[TokenTree]) - -> NamedParseResult { - let mut cur_eis = Vec::new(); - cur_eis.push(initial_matcher_pos(Rc::new(ms.iter() - .cloned() - .collect()), - None, - rdr.peek().sp.lo)); +pub fn parse(sess: &ParseSess, rdr: TtReader, ms: &[TokenTree]) -> NamedParseResult { + let mut parser = Parser::new_with_doc_flag(sess, Box::new(rdr), true); + let mut cur_eis = SmallVector::one(initial_matcher_pos(ms.to_owned(), None, parser.span.lo)); loop { let mut bb_eis = Vec::new(); // black-box parsed by parser.rs let mut next_eis = Vec::new(); // or proceed normally let mut eof_eis = Vec::new(); - let TokenAndSpan { tok, sp } = rdr.peek(); + let (sp, tok) = (parser.span, parser.token.clone()); /* we append new items to this while we go */ loop { @@ -425,8 +424,8 @@ pub fn parse(sess: &ParseSess, cur_eis.push(ei); } TokenTree::Token(_, ref t) => { - let mut ei_t = ei.clone(); if token_name_eq(t,&tok) { + let mut ei_t = ei.clone(); ei_t.idx += 1; next_eis.push(ei_t); } @@ -446,7 +445,7 @@ pub fn parse(sess: &ParseSess, } else if eof_eis.len() > 1 { return Error(sp, "ambiguity: multiple successful parses".to_string()); } else { - return Failure(sp, "unexpected end of macro invocation".to_string()); + return Failure(sp, token::Eof); } } else { if (!bb_eis.is_empty() && !next_eis.is_empty()) @@ -467,33 +466,25 @@ pub fn parse(sess: &ParseSess, } )) } else if bb_eis.is_empty() && next_eis.is_empty() { - return Failure(sp, format!("no rules expected the token `{}`", - pprust::token_to_string(&tok))); + return Failure(sp, tok); } else if !next_eis.is_empty() { /* Now process the next token */ while !next_eis.is_empty() { cur_eis.push(next_eis.pop().unwrap()); } - rdr.next_token(); + parser.bump(); } else /* bb_eis.len() == 1 */ { - let mut rust_parser = Parser::new(sess, cfg.clone(), Box::new(rdr.clone())); - let mut ei = bb_eis.pop().unwrap(); - match ei.top_elts.get_tt(ei.idx) { - TokenTree::Token(span, MatchNt(_, ident)) => { - let match_cur = ei.match_cur; - (&mut ei.matches[match_cur]).push(Rc::new(MatchedNonterminal( - parse_nt(&mut rust_parser, span, &ident.name.as_str())))); - ei.idx += 1; - ei.match_cur += 1; - } - _ => panic!() + if let TokenTree::Token(span, MatchNt(_, ident)) = ei.top_elts.get_tt(ei.idx) { + let match_cur = ei.match_cur; + (&mut ei.matches[match_cur]).push(Rc::new(MatchedNonterminal( + Rc::new(parse_nt(&mut parser, span, &ident.name.as_str()))))); + ei.idx += 1; + ei.match_cur += 1; + } else { + unreachable!() } cur_eis.push(ei); - - for _ in 0..rust_parser.tokens_consumed { - let _ = rdr.next_token(); - } } } @@ -505,10 +496,19 @@ pub fn parse_nt<'a>(p: &mut Parser<'a>, sp: Span, name: &str) -> Nonterminal { match name { "tt" => { p.quote_depth += 1; //but in theory, non-quoted tts might be useful - let res: ::parse::PResult<'a, _> = p.parse_token_tree(); - let res = token::NtTT(P(panictry!(res))); + let mut tt = panictry!(p.parse_token_tree()); p.quote_depth -= 1; - return res; + loop { + let nt = match tt { + TokenTree::Token(_, token::Interpolated(ref nt)) => nt.clone(), + _ => break, + }; + match *nt { + token::NtTT(ref sub_tt) => tt = sub_tt.clone(), + _ => break, + } + } + return token::NtTT(tt); } _ => {} } @@ -524,7 +524,7 @@ pub fn parse_nt<'a>(p: &mut Parser<'a>, sp: Span, name: &str) -> Nonterminal { }, "block" => token::NtBlock(panictry!(p.parse_block())), "stmt" => match panictry!(p.parse_stmt()) { - Some(s) => token::NtStmt(P(s)), + Some(s) => token::NtStmt(s), None => { p.fatal("expected a statement").emit(); panic!(FatalError); @@ -537,7 +537,7 @@ pub fn parse_nt<'a>(p: &mut Parser<'a>, sp: Span, name: &str) -> Nonterminal { "ident" => match p.token { token::Ident(sn) => { p.bump(); - token::NtIdent(Box::new(Spanned::{node: sn, span: p.span})) + token::NtIdent(Spanned::{node: sn, span: p.span}) } _ => { let token_str = pprust::token_to_string(&p.token); @@ -547,7 +547,7 @@ pub fn parse_nt<'a>(p: &mut Parser<'a>, sp: Span, name: &str) -> Nonterminal { } }, "path" => { - token::NtPath(Box::new(panictry!(p.parse_path(PathStyle::Type)))) + token::NtPath(panictry!(p.parse_path(PathStyle::Type))) }, "meta" => token::NtMeta(panictry!(p.parse_meta_item())), // this is not supposed to happen, since it has been checked diff --git a/src/libsyntax/ext/tt/macro_rules.rs b/src/libsyntax/ext/tt/macro_rules.rs index 9f4c0b5eb8..552d4de961 100644 --- a/src/libsyntax/ext/tt/macro_rules.rs +++ b/src/libsyntax/ext/tt/macro_rules.rs @@ -16,7 +16,7 @@ use ext::expand::{Expansion, ExpansionKind}; use ext::placeholders; use ext::tt::macro_parser::{Success, Error, Failure}; use ext::tt::macro_parser::{MatchedSeq, MatchedNonterminal}; -use ext::tt::macro_parser::parse; +use ext::tt::macro_parser::{parse, parse_failure_msg}; use parse::ParseSess; use parse::lexer::new_tt_reader; use parse::parser::{Parser, Restrictions}; @@ -58,7 +58,6 @@ impl<'a> ParserAnyMacro<'a> { struct MacroRulesMacroExpander { name: ast::Ident, - imported_from: Option, lhses: Vec, rhses: Vec, valid: bool, @@ -76,7 +75,6 @@ impl TTMacroExpander for MacroRulesMacroExpander { generic_extension(cx, sp, self.name, - self.imported_from, arg, &self.lhses, &self.rhses) @@ -87,7 +85,6 @@ impl TTMacroExpander for MacroRulesMacroExpander { fn generic_extension<'cx>(cx: &'cx ExtCtxt, sp: Span, name: ast::Ident, - imported_from: Option, arg: &[TokenTree], lhses: &[TokenTree], rhses: &[TokenTree]) @@ -100,7 +97,7 @@ fn generic_extension<'cx>(cx: &'cx ExtCtxt, // Which arm's failure should we report? (the one furthest along) let mut best_fail_spot = DUMMY_SP; - let mut best_fail_msg = "internal error: ran no matchers".to_string(); + let mut best_fail_tok = None; for (i, lhs) in lhses.iter().enumerate() { // try each arm's matchers let lhs_tt = match *lhs { @@ -116,13 +113,11 @@ fn generic_extension<'cx>(cx: &'cx ExtCtxt, _ => cx.span_bug(sp, "malformed macro rhs"), }; // rhs has holes ( `$id` and `$(...)` that need filled) - let trncbr = new_tt_reader(&cx.parse_sess.span_diagnostic, - Some(named_matches), - imported_from, - rhs); - let mut p = Parser::new(cx.parse_sess(), cx.cfg(), Box::new(trncbr)); + let trncbr = + new_tt_reader(&cx.parse_sess.span_diagnostic, Some(named_matches), rhs); + let mut p = Parser::new(cx.parse_sess(), Box::new(trncbr)); p.directory = cx.current_expansion.module.directory.clone(); - p.restrictions = match cx.current_expansion.in_block { + p.restrictions = match cx.current_expansion.no_noninline_mod { true => Restrictions::NO_NONINLINE_MOD, false => Restrictions::empty(), }; @@ -139,9 +134,9 @@ fn generic_extension<'cx>(cx: &'cx ExtCtxt, macro_ident: name }) } - Failure(sp, ref msg) => if sp.lo >= best_fail_spot.lo { + Failure(sp, tok) => if sp.lo >= best_fail_spot.lo { best_fail_spot = sp; - best_fail_msg = (*msg).clone(); + best_fail_tok = Some(tok); }, Error(err_sp, ref msg) => { cx.span_fatal(err_sp.substitute_dummy(sp), &msg[..]) @@ -149,7 +144,8 @@ fn generic_extension<'cx>(cx: &'cx ExtCtxt, } } - cx.span_fatal(best_fail_spot.substitute_dummy(sp), &best_fail_msg[..]); + let best_fail_msg = parse_failure_msg(best_fail_tok.expect("ran no matchers")); + cx.span_fatal(best_fail_spot.substitute_dummy(sp), &best_fail_msg); } pub struct MacroRulesExpander; @@ -161,14 +157,13 @@ impl IdentMacroExpander for MacroRulesExpander { tts: Vec, attrs: Vec) -> Box { + let export = attr::contains_name(&attrs, "macro_export"); let def = ast::MacroDef { ident: ident, id: ast::DUMMY_NODE_ID, span: span, imported_from: None, - use_locally: true, body: tts, - export: attr::contains_name(&attrs, "macro_export"), allow_internal_unstable: attr::contains_name(&attrs, "allow_internal_unstable"), attrs: attrs, }; @@ -180,7 +175,7 @@ impl IdentMacroExpander for MacroRulesExpander { MacEager::items(placeholders::macro_scope_placeholder().make_items()) }; - cx.resolver.add_macro(cx.current_expansion.mark, def); + cx.resolver.add_macro(cx.current_expansion.mark, def, export); result } } @@ -223,12 +218,16 @@ pub fn compile(sess: &ParseSess, def: &ast::MacroDef) -> SyntaxExtension { ]; // Parse the macro_rules! invocation (`none` is for no interpolations): - let arg_reader = new_tt_reader(&sess.span_diagnostic, None, None, def.body.clone()); + let arg_reader = new_tt_reader(&sess.span_diagnostic, None, def.body.clone()); - let argument_map = match parse(sess, Vec::new(), arg_reader, &argument_gram) { + let argument_map = match parse(sess, arg_reader, &argument_gram) { Success(m) => m, - Failure(sp, str) | Error(sp, str) => { - panic!(sess.span_diagnostic.span_fatal(sp.substitute_dummy(def.span), &str)); + Failure(sp, tok) => { + let s = parse_failure_msg(tok); + panic!(sess.span_diagnostic.span_fatal(sp.substitute_dummy(def.span), &s)); + } + Error(sp, s) => { + panic!(sess.span_diagnostic.span_fatal(sp.substitute_dummy(def.span), &s)); } }; @@ -237,12 +236,14 @@ pub fn compile(sess: &ParseSess, def: &ast::MacroDef) -> SyntaxExtension { // Extract the arguments: let lhses = match **argument_map.get(&lhs_nm).unwrap() { MatchedSeq(ref s, _) => { - s.iter().map(|m| match **m { - MatchedNonterminal(NtTT(ref tt)) => { - valid &= check_lhs_nt_follows(sess, tt); - (**tt).clone() + s.iter().map(|m| { + if let MatchedNonterminal(ref nt) = **m { + if let NtTT(ref tt) = **nt { + valid &= check_lhs_nt_follows(sess, tt); + return (*tt).clone(); + } } - _ => sess.span_diagnostic.span_bug(def.span, "wrong-structured lhs") + sess.span_diagnostic.span_bug(def.span, "wrong-structured lhs") }).collect::>() } _ => sess.span_diagnostic.span_bug(def.span, "wrong-structured lhs") @@ -250,9 +251,13 @@ pub fn compile(sess: &ParseSess, def: &ast::MacroDef) -> SyntaxExtension { let rhses = match **argument_map.get(&rhs_nm).unwrap() { MatchedSeq(ref s, _) => { - s.iter().map(|m| match **m { - MatchedNonterminal(NtTT(ref tt)) => (**tt).clone(), - _ => sess.span_diagnostic.span_bug(def.span, "wrong-structured rhs") + s.iter().map(|m| { + if let MatchedNonterminal(ref nt) = **m { + if let NtTT(ref tt) = **nt { + return (*tt).clone(); + } + } + sess.span_diagnostic.span_bug(def.span, "wrong-structured lhs") }).collect() } _ => sess.span_diagnostic.span_bug(def.span, "wrong-structured rhs") @@ -269,7 +274,6 @@ pub fn compile(sess: &ParseSess, def: &ast::MacroDef) -> SyntaxExtension { let exp: Box<_> = Box::new(MacroRulesMacroExpander { name: def.ident, - imported_from: def.imported_from, lhses: lhses, rhses: rhses, valid: valid, diff --git a/src/libsyntax/ext/tt/transcribe.rs b/src/libsyntax/ext/tt/transcribe.rs index 939425378d..37e329e5d3 100644 --- a/src/libsyntax/ext/tt/transcribe.rs +++ b/src/libsyntax/ext/tt/transcribe.rs @@ -10,14 +10,13 @@ use self::LockstepIterSize::*; use ast::Ident; -use syntax_pos::{Span, DUMMY_SP}; use errors::{Handler, DiagnosticBuilder}; use ext::tt::macro_parser::{NamedMatch, MatchedSeq, MatchedNonterminal}; -use parse::token::{DocComment, MatchNt, SubstNt}; -use parse::token::{Token, Interpolated, NtIdent, NtTT, SpecialMacroVar}; -use parse::token; +use parse::token::{self, MatchNt, SubstNt, Token, NtIdent}; use parse::lexer::TokenAndSpan; +use syntax_pos::{Span, DUMMY_SP}; use tokenstream::{self, TokenTree}; +use util::small_vector::SmallVector; use std::rc::Rc; use std::ops::Add; @@ -36,20 +35,16 @@ struct TtFrame { pub struct TtReader<'a> { pub sp_diag: &'a Handler, /// the unzipped tree: - stack: Vec, + stack: SmallVector, /* for MBE-style macro transcription */ interpolations: HashMap>, - imported_from: Option, - // Some => return imported_from as the next token - crate_name_next: Option, repeat_idx: Vec, repeat_len: Vec, /* cached: */ pub cur_tok: Token, pub cur_span: Span, /// Transform doc comments. Only useful in macro invocations - pub desugar_doc_comments: bool, pub fatal_errs: Vec>, } @@ -58,27 +53,11 @@ pub struct TtReader<'a> { /// (and should) be None. pub fn new_tt_reader(sp_diag: &Handler, interp: Option>>, - imported_from: Option, src: Vec) -> TtReader { - new_tt_reader_with_doc_flag(sp_diag, interp, imported_from, src, false) -} - -/// The extra `desugar_doc_comments` flag enables reading doc comments -/// like any other attribute which consists of `meta` and surrounding #[ ] tokens. -/// -/// This can do Macro-By-Example transcription. On the other hand, if -/// `src` contains no `TokenTree::Sequence`s, `MatchNt`s or `SubstNt`s, `interp` can -/// (and should) be None. -pub fn new_tt_reader_with_doc_flag(sp_diag: &Handler, - interp: Option>>, - imported_from: Option, - src: Vec, - desugar_doc_comments: bool) - -> TtReader { let mut r = TtReader { sp_diag: sp_diag, - stack: vec!(TtFrame { + stack: SmallVector::one(TtFrame { forest: TokenTree::Sequence(DUMMY_SP, Rc::new(tokenstream::SequenceRepetition { tts: src, // doesn't matter. This merely holds the root unzipping. @@ -92,11 +71,8 @@ pub fn new_tt_reader_with_doc_flag(sp_diag: &Handler, None => HashMap::new(), Some(x) => x, }, - imported_from: imported_from, - crate_name_next: None, repeat_idx: Vec::new(), repeat_len: Vec::new(), - desugar_doc_comments: desugar_doc_comments, /* dummy values, never read: */ cur_tok: token::Eof, cur_span: DUMMY_SP, @@ -184,14 +160,6 @@ pub fn tt_next_token(r: &mut TtReader) -> TokenAndSpan { sp: r.cur_span.clone(), }; loop { - match r.crate_name_next.take() { - None => (), - Some(sp) => { - r.cur_span = sp; - r.cur_tok = token::Ident(r.imported_from.unwrap()); - return ret_val; - }, - } let should_pop = match r.stack.last() { None => { assert_eq!(ret_val.tok, token::Eof); @@ -278,47 +246,35 @@ pub fn tt_next_token(r: &mut TtReader) -> TokenAndSpan { } // FIXME #2887: think about span stuff here TokenTree::Token(sp, SubstNt(ident)) => { + r.stack.last_mut().unwrap().idx += 1; match lookup_cur_matched(r, ident) { None => { - r.stack.last_mut().unwrap().idx += 1; r.cur_span = sp; r.cur_tok = SubstNt(ident); return ret_val; // this can't be 0 length, just like TokenTree::Delimited } - Some(cur_matched) => { - match *cur_matched { + Some(cur_matched) => if let MatchedNonterminal(ref nt) = *cur_matched { + match **nt { // sidestep the interpolation tricks for ident because // (a) idents can be in lots of places, so it'd be a pain // (b) we actually can, since it's a token. - MatchedNonterminal(NtIdent(ref sn)) => { - r.stack.last_mut().unwrap().idx += 1; + NtIdent(ref sn) => { r.cur_span = sn.span; r.cur_tok = token::Ident(sn.node); return ret_val; } - MatchedNonterminal(NtTT(ref tt)) => { - r.stack.push(TtFrame { - forest: TokenTree::Token(sp, Interpolated(NtTT(tt.clone()))), - idx: 0, - dotdotdoted: false, - sep: None, - }); - } - MatchedNonterminal(ref other_whole_nt) => { - r.stack.last_mut().unwrap().idx += 1; + _ => { // FIXME(pcwalton): Bad copy. r.cur_span = sp; - r.cur_tok = Interpolated((*other_whole_nt).clone()); + r.cur_tok = token::Interpolated(nt.clone()); return ret_val; } - MatchedSeq(..) => { - panic!(r.sp_diag.span_fatal( - sp, /* blame the macro writer */ - &format!("variable '{}' is still repeating at this depth", - ident))); - } } + } else { + panic!(r.sp_diag.span_fatal( + sp, /* blame the macro writer */ + &format!("variable '{}' is still repeating at this depth", ident))); } } } @@ -333,26 +289,6 @@ pub fn tt_next_token(r: &mut TtReader) -> TokenAndSpan { }); // if this could be 0-length, we'd need to potentially recur here } - TokenTree::Token(sp, DocComment(name)) if r.desugar_doc_comments => { - r.stack.push(TtFrame { - forest: TokenTree::Token(sp, DocComment(name)), - idx: 0, - dotdotdoted: false, - sep: None - }); - } - TokenTree::Token(sp, token::SpecialVarNt(SpecialMacroVar::CrateMacroVar)) => { - r.stack.last_mut().unwrap().idx += 1; - - if r.imported_from.is_some() { - r.cur_span = sp; - r.cur_tok = token::ModSep; - r.crate_name_next = Some(sp); - return ret_val; - } - - // otherwise emit nothing and proceed to the next token - } TokenTree::Token(sp, tok) => { r.cur_span = sp; r.cur_tok = tok; diff --git a/src/libsyntax/feature_gate.rs b/src/libsyntax/feature_gate.rs index 2f4aa2e58e..c5fae9f323 100644 --- a/src/libsyntax/feature_gate.rs +++ b/src/libsyntax/feature_gate.rs @@ -30,7 +30,7 @@ use ast::{self, NodeId, PatKind}; use attr; use codemap::{CodeMap, Spanned}; use syntax_pos::Span; -use errors::Handler; +use errors::{DiagnosticBuilder, Handler}; use visit::{self, FnKind, Visitor}; use parse::ParseSess; use parse::token::InternedString; @@ -167,6 +167,9 @@ declare_features! ( // RFC 1238 (active, dropck_parametricity, "1.3.0", Some(28498)), + // Allows using the may_dangle attribute; RFC 1327 + (active, dropck_eyepatch, "1.10.0", Some(34761)), + // Allows the use of custom attributes; RFC 572 (active, custom_attribute, "1.0.0", Some(29642)), @@ -265,9 +268,6 @@ declare_features! ( // Allows cfg(target_has_atomic = "..."). (active, cfg_target_has_atomic, "1.9.0", Some(32976)), - // Allows `..` in tuple (struct) patterns - (active, dotdot_in_tuple_patterns, "1.10.0", Some(33627)), - // Allows `impl Trait` in function return types. (active, conservative_impl_trait, "1.12.0", Some(34511)), @@ -289,7 +289,7 @@ declare_features! ( (active, item_like_imports, "1.13.0", Some(35120)), // Macros 1.1 - (active, rustc_macro, "1.13.0", Some(35900)), + (active, proc_macro, "1.13.0", Some(35900)), // Allows untagged unions `union U { ... }` (active, untagged_unions, "1.13.0", Some(32836)), @@ -300,6 +300,18 @@ declare_features! ( // Used to identify the `compiler_builtins` crate // rustc internal (active, compiler_builtins, "1.13.0", None), + + // Allows attributes on lifetime/type formal parameters in generics (RFC 1327) + (active, generic_param_attrs, "1.11.0", Some(34761)), + + // Allows field shorthands (`x` meaning `x: x`) in struct literal expressions. + (active, field_init_shorthand, "1.14.0", Some(37340)), + + // The #![windows_subsystem] attribute + (active, windows_subsystem, "1.14.0", Some(37499)), + + // Allows using `Self` and associated types in struct expressions and patterns. + (active, more_struct_aliases, "1.14.0", Some(37544)), ); declare_features! ( @@ -344,6 +356,8 @@ declare_features! ( (accepted, deprecated, "1.9.0", Some(29935)), // `expr?` (accepted, question_mark, "1.14.0", Some(31436)), + // Allows `..` in tuple (struct) patterns + (accepted, dotdot_in_tuple_patterns, "1.14.0", Some(33627)), ); // (changing above list without updating src/doc/reference.md makes @cmr sad) @@ -365,17 +379,34 @@ pub enum AttributeType { pub enum AttributeGate { /// Is gated by a given feature gate, reason /// and function to check if enabled - Gated(&'static str, &'static str, fn(&Features) -> bool), + Gated(Stability, &'static str, &'static str, fn(&Features) -> bool), /// Ungated attribute, can be used on all release channels Ungated, } +impl AttributeGate { + fn is_deprecated(&self) -> bool { + match *self { + Gated(Stability::Deprecated(_), ..) => true, + _ => false, + } + } +} + +#[derive(Copy, Clone, PartialEq, Eq, Debug)] +pub enum Stability { + Unstable, + // Argument is tracking issue link. + Deprecated(&'static str), +} + // fn() is not Debug impl ::std::fmt::Debug for AttributeGate { fn fmt(&self, fmt: &mut ::std::fmt::Formatter) -> ::std::fmt::Result { match *self { - Gated(ref name, ref expl, _) => write!(fmt, "Gated({}, {})", name, expl), + Gated(ref stab, ref name, ref expl, _) => + write!(fmt, "Gated({:?}, {}, {})", stab, name, expl), Ungated => write!(fmt, "Ungated") } } @@ -390,6 +421,10 @@ macro_rules! cfg_fn { }} } +pub fn deprecated_attributes() -> Vec<&'static (&'static str, AttributeType, AttributeGate)> { + KNOWN_ATTRIBUTES.iter().filter(|a| a.2.is_deprecated()).collect() +} + // Attributes that have a special meaning to rustc or rustdoc pub const KNOWN_ATTRIBUTES: &'static [(&'static str, AttributeType, AttributeGate)] = &[ // Normal attributes @@ -426,7 +461,8 @@ pub const KNOWN_ATTRIBUTES: &'static [(&'static str, AttributeType, AttributeGat ("macro_escape", Normal, Ungated), // RFC #1445. - ("structural_match", Whitelisted, Gated("structural_match", + ("structural_match", Whitelisted, Gated(Stability::Unstable, + "structural_match", "the semantics of constant patterns is \ not yet settled", cfg_fn!(structural_match))), @@ -434,150 +470,181 @@ pub const KNOWN_ATTRIBUTES: &'static [(&'static str, AttributeType, AttributeGat // Not used any more, but we can't feature gate it ("no_stack_check", Normal, Ungated), - ("plugin", CrateLevel, Gated("plugin", + ("plugin", CrateLevel, Gated(Stability::Unstable, + "plugin", "compiler plugins are experimental \ and possibly buggy", cfg_fn!(plugin))), ("no_std", CrateLevel, Ungated), - ("no_core", CrateLevel, Gated("no_core", + ("no_core", CrateLevel, Gated(Stability::Unstable, + "no_core", "no_core is experimental", cfg_fn!(no_core))), - ("lang", Normal, Gated("lang_items", + ("lang", Normal, Gated(Stability::Unstable, + "lang_items", "language items are subject to change", cfg_fn!(lang_items))), - ("linkage", Whitelisted, Gated("linkage", + ("linkage", Whitelisted, Gated(Stability::Unstable, + "linkage", "the `linkage` attribute is experimental \ and not portable across platforms", cfg_fn!(linkage))), - ("thread_local", Whitelisted, Gated("thread_local", + ("thread_local", Whitelisted, Gated(Stability::Unstable, + "thread_local", "`#[thread_local]` is an experimental feature, and does \ not currently handle destructors. There is no \ corresponding `#[task_local]` mapping to the task \ model", cfg_fn!(thread_local))), - ("rustc_on_unimplemented", Normal, Gated("on_unimplemented", + ("rustc_on_unimplemented", Normal, Gated(Stability::Unstable, + "on_unimplemented", "the `#[rustc_on_unimplemented]` attribute \ is an experimental feature", cfg_fn!(on_unimplemented))), - ("allocator", Whitelisted, Gated("allocator", + ("allocator", Whitelisted, Gated(Stability::Unstable, + "allocator", "the `#[allocator]` attribute is an experimental feature", cfg_fn!(allocator))), - ("needs_allocator", Normal, Gated("needs_allocator", + ("needs_allocator", Normal, Gated(Stability::Unstable, + "needs_allocator", "the `#[needs_allocator]` \ attribute is an experimental \ feature", cfg_fn!(needs_allocator))), - ("panic_runtime", Whitelisted, Gated("panic_runtime", + ("panic_runtime", Whitelisted, Gated(Stability::Unstable, + "panic_runtime", "the `#[panic_runtime]` attribute is \ an experimental feature", cfg_fn!(panic_runtime))), - ("needs_panic_runtime", Whitelisted, Gated("needs_panic_runtime", + ("needs_panic_runtime", Whitelisted, Gated(Stability::Unstable, + "needs_panic_runtime", "the `#[needs_panic_runtime]` \ attribute is an experimental \ feature", cfg_fn!(needs_panic_runtime))), - ("rustc_variance", Normal, Gated("rustc_attrs", + ("rustc_variance", Normal, Gated(Stability::Unstable, + "rustc_attrs", "the `#[rustc_variance]` attribute \ is just used for rustc unit tests \ and will never be stable", cfg_fn!(rustc_attrs))), - ("rustc_error", Whitelisted, Gated("rustc_attrs", + ("rustc_error", Whitelisted, Gated(Stability::Unstable, + "rustc_attrs", "the `#[rustc_error]` attribute \ is just used for rustc unit tests \ and will never be stable", cfg_fn!(rustc_attrs))), - ("rustc_if_this_changed", Whitelisted, Gated("rustc_attrs", + ("rustc_if_this_changed", Whitelisted, Gated(Stability::Unstable, + "rustc_attrs", "the `#[rustc_if_this_changed]` attribute \ is just used for rustc unit tests \ and will never be stable", cfg_fn!(rustc_attrs))), - ("rustc_then_this_would_need", Whitelisted, Gated("rustc_attrs", + ("rustc_then_this_would_need", Whitelisted, Gated(Stability::Unstable, + "rustc_attrs", "the `#[rustc_if_this_changed]` attribute \ is just used for rustc unit tests \ and will never be stable", cfg_fn!(rustc_attrs))), - ("rustc_dirty", Whitelisted, Gated("rustc_attrs", + ("rustc_dirty", Whitelisted, Gated(Stability::Unstable, + "rustc_attrs", "the `#[rustc_dirty]` attribute \ is just used for rustc unit tests \ and will never be stable", cfg_fn!(rustc_attrs))), - ("rustc_clean", Whitelisted, Gated("rustc_attrs", + ("rustc_clean", Whitelisted, Gated(Stability::Unstable, + "rustc_attrs", "the `#[rustc_clean]` attribute \ is just used for rustc unit tests \ and will never be stable", cfg_fn!(rustc_attrs))), - ("rustc_metadata_dirty", Whitelisted, Gated("rustc_attrs", + ("rustc_metadata_dirty", Whitelisted, Gated(Stability::Unstable, + "rustc_attrs", "the `#[rustc_metadata_dirty]` attribute \ is just used for rustc unit tests \ and will never be stable", cfg_fn!(rustc_attrs))), - ("rustc_metadata_clean", Whitelisted, Gated("rustc_attrs", + ("rustc_metadata_clean", Whitelisted, Gated(Stability::Unstable, + "rustc_attrs", "the `#[rustc_metadata_clean]` attribute \ is just used for rustc unit tests \ and will never be stable", cfg_fn!(rustc_attrs))), - ("rustc_partition_reused", Whitelisted, Gated("rustc_attrs", + ("rustc_partition_reused", Whitelisted, Gated(Stability::Unstable, + "rustc_attrs", "this attribute \ is just used for rustc unit tests \ and will never be stable", cfg_fn!(rustc_attrs))), - ("rustc_partition_translated", Whitelisted, Gated("rustc_attrs", + ("rustc_partition_translated", Whitelisted, Gated(Stability::Unstable, + "rustc_attrs", "this attribute \ is just used for rustc unit tests \ and will never be stable", cfg_fn!(rustc_attrs))), - ("rustc_symbol_name", Whitelisted, Gated("rustc_attrs", + ("rustc_symbol_name", Whitelisted, Gated(Stability::Unstable, + "rustc_attrs", "internal rustc attributes will never be stable", cfg_fn!(rustc_attrs))), - ("rustc_item_path", Whitelisted, Gated("rustc_attrs", + ("rustc_item_path", Whitelisted, Gated(Stability::Unstable, + "rustc_attrs", "internal rustc attributes will never be stable", cfg_fn!(rustc_attrs))), - ("rustc_move_fragments", Normal, Gated("rustc_attrs", + ("rustc_move_fragments", Normal, Gated(Stability::Unstable, + "rustc_attrs", "the `#[rustc_move_fragments]` attribute \ is just used for rustc unit tests \ and will never be stable", cfg_fn!(rustc_attrs))), - ("rustc_mir", Whitelisted, Gated("rustc_attrs", + ("rustc_mir", Whitelisted, Gated(Stability::Unstable, + "rustc_attrs", "the `#[rustc_mir]` attribute \ is just used for rustc unit tests \ and will never be stable", cfg_fn!(rustc_attrs))), - ("rustc_inherit_overflow_checks", Whitelisted, Gated("rustc_attrs", + ("rustc_inherit_overflow_checks", Whitelisted, Gated(Stability::Unstable, + "rustc_attrs", "the `#[rustc_inherit_overflow_checks]` \ attribute is just used to control \ overflow checking behavior of several \ libcore functions that are inlined \ across crates and will never be stable", cfg_fn!(rustc_attrs))), - ("compiler_builtins", Whitelisted, Gated("compiler_builtins", + ("compiler_builtins", Whitelisted, Gated(Stability::Unstable, + "compiler_builtins", "the `#[compiler_builtins]` attribute is used to \ identify the `compiler_builtins` crate which \ contains compiler-rt intrinsics and will never be \ stable", cfg_fn!(compiler_builtins))), - ("allow_internal_unstable", Normal, Gated("allow_internal_unstable", + ("allow_internal_unstable", Normal, Gated(Stability::Unstable, + "allow_internal_unstable", EXPLAIN_ALLOW_INTERNAL_UNSTABLE, cfg_fn!(allow_internal_unstable))), - ("fundamental", Whitelisted, Gated("fundamental", + ("fundamental", Whitelisted, Gated(Stability::Unstable, + "fundamental", "the `#[fundamental]` attribute \ is an experimental feature", cfg_fn!(fundamental))), - ("linked_from", Normal, Gated("linked_from", + ("linked_from", Normal, Gated(Stability::Unstable, + "linked_from", "the `#[linked_from]` attribute \ is an experimental feature", cfg_fn!(linked_from))), - ("rustc_macro_derive", Normal, Gated("rustc_macro", - "the `#[rustc_macro_derive]` attribute \ - is an experimental feature", - cfg_fn!(rustc_macro))), + ("proc_macro_derive", Normal, Gated(Stability::Unstable, + "proc_macro", + "the `#[proc_macro_derive]` attribute \ + is an experimental feature", + cfg_fn!(proc_macro))), - ("rustc_copy_clone_marker", Whitelisted, Gated("rustc_attrs", + ("rustc_copy_clone_marker", Whitelisted, Gated(Stability::Unstable, + "rustc_attrs", "internal implementation detail", cfg_fn!(rustc_attrs))), @@ -587,7 +654,8 @@ pub const KNOWN_ATTRIBUTES: &'static [(&'static str, AttributeType, AttributeGat // FIXME: #14406 these are processed in trans, which happens after the // lint pass ("cold", Whitelisted, Ungated), - ("naked", Whitelisted, Gated("naked_functions", + ("naked", Whitelisted, Gated(Stability::Unstable, + "naked_functions", "the `#[naked]` attribute \ is an experimental feature", cfg_fn!(naked_functions))), @@ -598,26 +666,38 @@ pub const KNOWN_ATTRIBUTES: &'static [(&'static str, AttributeType, AttributeGat ("link_section", Whitelisted, Ungated), ("no_builtins", Whitelisted, Ungated), ("no_mangle", Whitelisted, Ungated), - ("no_debug", Whitelisted, Gated("no_debug", - "the `#[no_debug]` attribute \ - is an experimental feature", - cfg_fn!(no_debug))), - ("omit_gdb_pretty_printer_section", Whitelisted, Gated("omit_gdb_pretty_printer_section", + ("no_debug", Whitelisted, Gated( + Stability::Deprecated("https://github.com/rust-lang/rust/issues/29721"), + "no_debug", + "the `#[no_debug]` attribute is an experimental feature", + cfg_fn!(no_debug))), + ("omit_gdb_pretty_printer_section", Whitelisted, Gated(Stability::Unstable, + "omit_gdb_pretty_printer_section", "the `#[omit_gdb_pretty_printer_section]` \ attribute is just used for the Rust test \ suite", cfg_fn!(omit_gdb_pretty_printer_section))), ("unsafe_destructor_blind_to_params", Normal, - Gated("dropck_parametricity", + Gated(Stability::Unstable, + "dropck_parametricity", "unsafe_destructor_blind_to_params has unstable semantics \ and may be removed in the future", cfg_fn!(dropck_parametricity))), - ("unwind", Whitelisted, Gated("unwind_attributes", "#[unwind] is experimental", + ("may_dangle", + Normal, + Gated(Stability::Unstable, + "dropck_eyepatch", + "may_dangle has unstable semantics and may be removed in the future", + cfg_fn!(dropck_eyepatch))), + ("unwind", Whitelisted, Gated(Stability::Unstable, + "unwind_attributes", + "#[unwind] is experimental", cfg_fn!(unwind_attributes))), // used in resolve - ("prelude_import", Whitelisted, Gated("prelude_import", + ("prelude_import", Whitelisted, Gated(Stability::Unstable, + "prelude_import", "`#[prelude_import]` is for use by rustc only", cfg_fn!(prelude_import))), @@ -629,13 +709,21 @@ pub const KNOWN_ATTRIBUTES: &'static [(&'static str, AttributeType, AttributeGat ("unstable", Whitelisted, Ungated), ("deprecated", Normal, Ungated), - ("rustc_paren_sugar", Normal, Gated("unboxed_closures", + ("rustc_paren_sugar", Normal, Gated(Stability::Unstable, + "unboxed_closures", "unboxed_closures are still evolving", cfg_fn!(unboxed_closures))), - ("rustc_reflect_like", Whitelisted, Gated("reflect", + ("rustc_reflect_like", Whitelisted, Gated(Stability::Unstable, + "reflect", "defining reflective traits is still evolving", cfg_fn!(reflect))), + ("windows_subsystem", Whitelisted, Gated(Stability::Unstable, + "windows_subsystem", + "the windows subsystem attribute \ + is currently unstable", + cfg_fn!(windows_subsystem))), + // Crate level attributes ("crate_name", CrateLevel, Ungated), ("crate_type", CrateLevel, Ungated), @@ -654,7 +742,7 @@ const GATED_CFGS: &'static [(&'static str, &'static str, fn(&Features) -> bool)] ("target_vendor", "cfg_target_vendor", cfg_fn!(cfg_target_vendor)), ("target_thread_local", "cfg_target_thread_local", cfg_fn!(cfg_target_thread_local)), ("target_has_atomic", "cfg_target_has_atomic", cfg_fn!(cfg_target_has_atomic)), - ("rustc_macro", "rustc_macro", cfg_fn!(rustc_macro)), + ("proc_macro", "proc_macro", cfg_fn!(proc_macro)), ]; #[derive(Debug, Eq, PartialEq)] @@ -715,7 +803,7 @@ impl<'a> Context<'a> { let name = &*attr.name(); for &(n, ty, ref gateage) in KNOWN_ATTRIBUTES { if n == name { - if let &Gated(ref name, ref desc, ref has_feature) = gateage { + if let &Gated(_, ref name, ref desc, ref has_feature) = gateage { gate_feature_fn!(self, has_feature, attr.span, name, desc); } debug!("check_attribute: {:?} is known, {:?}, {:?}", name, ty, gateage); @@ -789,6 +877,11 @@ pub enum GateIssue { pub fn emit_feature_err(sess: &ParseSess, feature: &str, span: Span, issue: GateIssue, explain: &str) { + feature_err(sess, feature, span, issue, explain).emit(); +} + +pub fn feature_err<'a>(sess: &'a ParseSess, feature: &str, span: Span, issue: GateIssue, + explain: &str) -> DiagnosticBuilder<'a> { let diag = &sess.span_diagnostic; let issue = match issue { @@ -809,7 +902,7 @@ pub fn emit_feature_err(sess: &ParseSess, feature: &str, span: Span, issue: Gate feature)); } - err.emit(); + err } const EXPLAIN_BOX_SYNTAX: &'static str = @@ -833,7 +926,12 @@ pub const EXPLAIN_ALLOW_INTERNAL_UNSTABLE: &'static str = "allow_internal_unstable side-steps feature gating and stability checks"; pub const EXPLAIN_CUSTOM_DERIVE: &'static str = - "`#[derive]` for custom traits is not stable enough for use and is subject to change"; + "`#[derive]` for custom traits is not stable enough for use. It is deprecated and will \ + be removed in v1.15"; + +pub const EXPLAIN_DEPR_CUSTOM_DERIVE: &'static str = + "`#[derive]` for custom traits is deprecated and will be removed in v1.15. Prefer using \ + procedural macro custom derive"; pub const EXPLAIN_DERIVE_UNDERSCORE: &'static str = "attributes of the form `#[derive_*]` are reserved for the compiler"; @@ -1071,6 +1169,14 @@ impl<'a> Visitor for PostExpansionVisitor<'a> { ast::ExprKind::InPlace(..) => { gate_feature_post!(&self, placement_in_syntax, e.span, EXPLAIN_PLACEMENT_IN); } + ast::ExprKind::Struct(_, ref fields, _) => { + for field in fields { + if field.is_shorthand { + gate_feature_post!(&self, field_init_shorthand, field.span, + "struct field shorthands are unstable"); + } + } + } _ => {} } visit::walk_expr(self, e); @@ -1078,14 +1184,14 @@ impl<'a> Visitor for PostExpansionVisitor<'a> { fn visit_pat(&mut self, pattern: &ast::Pat) { match pattern.node { - PatKind::Vec(_, Some(_), ref last) if !last.is_empty() => { + PatKind::Slice(_, Some(_), ref last) if !last.is_empty() => { gate_feature_post!(&self, advanced_slice_patterns, pattern.span, "multiple-element slice matches anywhere \ but at the end of a slice (e.g. \ `[0, ..xs, 0]`) are experimental") } - PatKind::Vec(..) => { + PatKind::Slice(..) => { gate_feature_post!(&self, slice_patterns, pattern.span, "slice pattern syntax is experimental"); @@ -1095,18 +1201,6 @@ impl<'a> Visitor for PostExpansionVisitor<'a> { pattern.span, "box pattern syntax is experimental"); } - PatKind::Tuple(_, ddpos) - if ddpos.is_some() => { - gate_feature_post!(&self, dotdot_in_tuple_patterns, - pattern.span, - "`..` in tuple patterns is experimental"); - } - PatKind::TupleStruct(_, ref fields, ddpos) - if ddpos.is_some() && !fields.is_empty() => { - gate_feature_post!(&self, dotdot_in_tuple_patterns, - pattern.span, - "`..` in tuple struct patterns is experimental"); - } PatKind::TupleStruct(_, ref fields, ddpos) if ddpos.is_none() && fields.is_empty() => { gate_feature_post!(&self, relaxed_adts, pattern.span, @@ -1216,6 +1310,24 @@ impl<'a> Visitor for PostExpansionVisitor<'a> { visit::walk_vis(self, vis) } + + fn visit_generics(&mut self, g: &ast::Generics) { + for t in &g.ty_params { + if !t.attrs.is_empty() { + gate_feature_post!(&self, generic_param_attrs, t.attrs[0].span, + "attributes on type parameter bindings are experimental"); + } + } + visit::walk_generics(self, g) + } + + fn visit_lifetime_def(&mut self, lifetime_def: &ast::LifetimeDef) { + if !lifetime_def.attrs.is_empty() { + gate_feature_post!(&self, generic_param_attrs, lifetime_def.attrs[0].span, + "attributes on lifetime bindings are experimental"); + } + visit::walk_lifetime_def(self, lifetime_def) + } } pub fn get_features(span_handler: &Handler, krate_attrs: &[ast::Attribute]) -> Features { @@ -1283,7 +1395,7 @@ pub enum UnstableFeatures { /// Hard errors for unstable features are active, as on /// beta/stable channels. Disallow, - /// Allow features to me activated, as on nightly. + /// Allow features to be activated, as on nightly. Allow, /// Errors are bypassed for bootstrapping. This is required any time /// during the build that feature-related lints are set to warn or above diff --git a/src/libsyntax/fold.rs b/src/libsyntax/fold.rs index 36f273e1db..1deeaf4223 100644 --- a/src/libsyntax/fold.rs +++ b/src/libsyntax/fold.rs @@ -356,7 +356,7 @@ pub fn noop_fold_ty(t: P, fld: &mut T) -> P { id: fld.new_id(id), node: match node { TyKind::Infer | TyKind::ImplicitSelf => node, - TyKind::Vec(ty) => TyKind::Vec(fld.fold_ty(ty)), + TyKind::Slice(ty) => TyKind::Slice(fld.fold_ty(ty)), TyKind::Ptr(mt) => TyKind::Ptr(fld.fold_mt(mt)), TyKind::Rptr(region, mt) => { TyKind::Rptr(fld.fold_opt_lifetime(region), fld.fold_mt(mt)) @@ -385,8 +385,8 @@ pub fn noop_fold_ty(t: P, fld: &mut T) -> P { TyKind::ObjectSum(fld.fold_ty(ty), fld.fold_bounds(bounds)) } - TyKind::FixedLengthVec(ty, e) => { - TyKind::FixedLengthVec(fld.fold_ty(ty), fld.fold_expr(e)) + TyKind::Array(ty, e) => { + TyKind::Array(fld.fold_ty(ty), fld.fold_expr(e)) } TyKind::Typeof(expr) => { TyKind::Typeof(fld.fold_expr(expr)) @@ -576,7 +576,13 @@ pub fn noop_fold_token(t: token::Token, fld: &mut T) -> token::Token match t { token::Ident(id) => token::Ident(fld.fold_ident(id)), token::Lifetime(id) => token::Lifetime(fld.fold_ident(id)), - token::Interpolated(nt) => token::Interpolated(fld.fold_interpolated(nt)), + token::Interpolated(nt) => { + let nt = match Rc::try_unwrap(nt) { + Ok(nt) => nt, + Err(nt) => (*nt).clone(), + }; + token::Interpolated(Rc::new(fld.fold_interpolated(nt))) + } token::SubstNt(ident) => token::SubstNt(fld.fold_ident(ident)), token::MatchNt(name, kind) => token::MatchNt(fld.fold_ident(name), fld.fold_ident(kind)), _ => t @@ -614,26 +620,25 @@ pub fn noop_fold_interpolated(nt: token::Nonterminal, fld: &mut T) .expect_one("expected fold to produce exactly one item")), token::NtBlock(block) => token::NtBlock(fld.fold_block(block)), token::NtStmt(stmt) => - token::NtStmt(stmt.map(|stmt| fld.fold_stmt(stmt) + token::NtStmt(fld.fold_stmt(stmt) // this is probably okay, because the only folds likely // to peek inside interpolated nodes will be renamings/markings, // which map single items to single items - .expect_one("expected fold to produce exactly one statement"))), + .expect_one("expected fold to produce exactly one statement")), token::NtPat(pat) => token::NtPat(fld.fold_pat(pat)), token::NtExpr(expr) => token::NtExpr(fld.fold_expr(expr)), token::NtTy(ty) => token::NtTy(fld.fold_ty(ty)), - token::NtIdent(id) => - token::NtIdent(Box::new(Spanned::{node: fld.fold_ident(id.node), ..*id})), + token::NtIdent(id) => token::NtIdent(Spanned::{node: fld.fold_ident(id.node), ..id}), token::NtMeta(meta_item) => token::NtMeta(fld.fold_meta_item(meta_item)), - token::NtPath(path) => token::NtPath(Box::new(fld.fold_path(*path))), - token::NtTT(tt) => token::NtTT(P(fld.fold_tt(&tt))), + token::NtPath(path) => token::NtPath(fld.fold_path(path)), + token::NtTT(tt) => token::NtTT(fld.fold_tt(&tt)), token::NtArm(arm) => token::NtArm(fld.fold_arm(arm)), - token::NtImplItem(arm) => - token::NtImplItem(arm.map(|arm| fld.fold_impl_item(arm) - .expect_one("expected fold to produce exactly one item"))), - token::NtTraitItem(arm) => - token::NtTraitItem(arm.map(|arm| fld.fold_trait_item(arm) - .expect_one("expected fold to produce exactly one item"))), + token::NtImplItem(item) => + token::NtImplItem(fld.fold_impl_item(item) + .expect_one("expected fold to produce exactly one item")), + token::NtTraitItem(item) => + token::NtTraitItem(fld.fold_trait_item(item) + .expect_one("expected fold to produce exactly one item")), token::NtGenerics(generics) => token::NtGenerics(fld.fold_generics(generics)), token::NtWhereClause(where_clause) => token::NtWhereClause(fld.fold_where_clause(where_clause)), @@ -662,8 +667,13 @@ pub fn noop_fold_ty_param_bound(tpb: TyParamBound, fld: &mut T) } pub fn noop_fold_ty_param(tp: TyParam, fld: &mut T) -> TyParam { - let TyParam {id, ident, bounds, default, span} = tp; + let TyParam {attrs, id, ident, bounds, default, span} = tp; + let attrs: Vec<_> = attrs.into(); TyParam { + attrs: attrs.into_iter() + .flat_map(|x| fld.fold_attribute(x).into_iter()) + .collect::>() + .into(), id: fld.new_id(id), ident: ident, bounds: fld.fold_bounds(bounds), @@ -687,7 +697,12 @@ pub fn noop_fold_lifetime(l: Lifetime, fld: &mut T) -> Lifetime { pub fn noop_fold_lifetime_def(l: LifetimeDef, fld: &mut T) -> LifetimeDef { + let attrs: Vec<_> = l.attrs.into(); LifetimeDef { + attrs: attrs.into_iter() + .flat_map(|x| fld.fold_attribute(x).into_iter()) + .collect::>() + .into(), lifetime: fld.fold_lifetime(l.lifetime), bounds: fld.fold_lifetimes(l.bounds), } @@ -813,11 +828,12 @@ pub fn noop_fold_struct_field(f: StructField, fld: &mut T) -> StructF } } -pub fn noop_fold_field(Field {ident, expr, span}: Field, folder: &mut T) -> Field { +pub fn noop_fold_field(f: Field, folder: &mut T) -> Field { Field { - ident: respan(ident.span, folder.fold_ident(ident.node)), - expr: folder.fold_expr(expr), - span: folder.new_span(span) + ident: respan(f.ident.span, folder.fold_ident(f.ident.node)), + expr: folder.fold_expr(f.expr), + span: folder.new_span(f.span), + is_shorthand: f.is_shorthand, } } @@ -961,10 +977,8 @@ pub fn noop_fold_mod(Mod {inner, items}: Mod, folder: &mut T) -> Mod } } -pub fn noop_fold_crate(Crate {module, attrs, config, mut exported_macros, span}: Crate, +pub fn noop_fold_crate(Crate {module, attrs, mut exported_macros, span}: Crate, folder: &mut T) -> Crate { - let config = folder.fold_meta_items(config); - let mut items = folder.fold_item(P(ast::Item { ident: keywords::Invalid.ident(), attrs: attrs, @@ -998,7 +1012,6 @@ pub fn noop_fold_crate(Crate {module, attrs, config, mut exported_mac Crate { module: module, attrs: attrs, - config: config, exported_macros: exported_macros, span: span, } @@ -1092,8 +1105,8 @@ pub fn noop_fold_pat(p: P, folder: &mut T) -> P { PatKind::Range(e1, e2) => { PatKind::Range(folder.fold_expr(e1), folder.fold_expr(e2)) }, - PatKind::Vec(before, slice, after) => { - PatKind::Vec(before.move_map(|x| folder.fold_pat(x)), + PatKind::Slice(before, slice, after) => { + PatKind::Slice(before.move_map(|x| folder.fold_pat(x)), slice.map(|x| folder.fold_pat(x)), after.move_map(|x| folder.fold_pat(x))) } @@ -1236,36 +1249,22 @@ pub fn noop_fold_expr(Expr {id, node, span, attrs}: Expr, folder: &mu folder.fold_ident(label.node))) ), ExprKind::Ret(e) => ExprKind::Ret(e.map(|x| folder.fold_expr(x))), - ExprKind::InlineAsm(InlineAsm { - inputs, - outputs, - asm, - asm_str_style, - clobbers, - volatile, - alignstack, - dialect, - expn_id, - }) => ExprKind::InlineAsm(InlineAsm { - inputs: inputs.move_map(|(c, input)| { - (c, folder.fold_expr(input)) - }), - outputs: outputs.move_map(|out| { - InlineAsmOutput { - constraint: out.constraint, - expr: folder.fold_expr(out.expr), - is_rw: out.is_rw, - is_indirect: out.is_indirect, - } - }), - asm: asm, - asm_str_style: asm_str_style, - clobbers: clobbers, - volatile: volatile, - alignstack: alignstack, - dialect: dialect, - expn_id: expn_id, - }), + ExprKind::InlineAsm(asm) => ExprKind::InlineAsm(asm.map(|asm| { + InlineAsm { + inputs: asm.inputs.move_map(|(c, input)| { + (c, folder.fold_expr(input)) + }), + outputs: asm.outputs.move_map(|out| { + InlineAsmOutput { + constraint: out.constraint, + expr: folder.fold_expr(out.expr), + is_rw: out.is_rw, + is_indirect: out.is_indirect, + } + }), + ..asm + } + })), ExprKind::Mac(mac) => ExprKind::Mac(folder.fold_mac(mac)), ExprKind::Struct(path, fields, maybe_expr) => { ExprKind::Struct(folder.fold_path(path), diff --git a/src/libsyntax/json.rs b/src/libsyntax/json.rs index a40c30b3e3..a1c273baee 100644 --- a/src/libsyntax/json.rs +++ b/src/libsyntax/json.rs @@ -38,14 +38,24 @@ pub struct JsonEmitter { } impl JsonEmitter { + pub fn stderr(registry: Option, + code_map: Rc) -> JsonEmitter { + JsonEmitter { + dst: Box::new(io::stderr()), + registry: registry, + cm: code_map, + } + } + pub fn basic() -> JsonEmitter { JsonEmitter::stderr(None, Rc::new(CodeMap::new())) } - pub fn stderr(registry: Option, - code_map: Rc) -> JsonEmitter { + pub fn new(dst: Box, + registry: Option, + code_map: Rc) -> JsonEmitter { JsonEmitter { - dst: Box::new(io::stderr()), + dst: dst, registry: registry, cm: code_map, } diff --git a/src/libsyntax/lib.rs b/src/libsyntax/lib.rs index 6e671c9efd..feed400897 100644 --- a/src/libsyntax/lib.rs +++ b/src/libsyntax/lib.rs @@ -34,7 +34,9 @@ #![cfg_attr(stage0, feature(question_mark))] #![feature(rustc_diagnostic_macros)] #![feature(specialization)] +#![cfg_attr(stage0, feature(dotdot_in_tuple_patterns))] +extern crate core; extern crate serialize; extern crate term; extern crate libc; diff --git a/src/libsyntax/parse/attr.rs b/src/libsyntax/parse/attr.rs index 9eac024edb..983c882eaf 100644 --- a/src/libsyntax/parse/attr.rs +++ b/src/libsyntax/parse/attr.rs @@ -126,7 +126,7 @@ impl<'a> Parser<'a> { self.expect(&token::OpenDelim(token::Bracket))?; let meta_item = self.parse_meta_item()?; self.expect(&token::CloseDelim(token::Bracket))?; - let hi = self.last_span.hi; + let hi = self.prev_span.hi; (mk_sp(lo, hi), meta_item, style) } @@ -215,7 +215,10 @@ impl<'a> Parser<'a> { /// meta_item_inner : (meta_item | UNSUFFIXED_LIT) (',' meta_item_inner)? ; pub fn parse_meta_item(&mut self) -> PResult<'a, P> { let nt_meta = match self.token { - token::Interpolated(token::NtMeta(ref e)) => Some(e.clone()), + token::Interpolated(ref nt) => match **nt { + token::NtMeta(ref e) => Some(e.clone()), + _ => None, + }, _ => None, }; @@ -231,16 +234,16 @@ impl<'a> Parser<'a> { token::Eq => { self.bump(); let lit = self.parse_unsuffixed_lit()?; - let hi = self.last_span.hi; + let hi = self.prev_span.hi; Ok(P(spanned(lo, hi, ast::MetaItemKind::NameValue(name, lit)))) } token::OpenDelim(token::Paren) => { let inner_items = self.parse_meta_seq()?; - let hi = self.last_span.hi; + let hi = self.prev_span.hi; Ok(P(spanned(lo, hi, ast::MetaItemKind::List(name, inner_items)))) } _ => { - let hi = self.last_span.hi; + let hi = self.prev_span.hi; Ok(P(spanned(lo, hi, ast::MetaItemKind::Word(name)))) } } @@ -253,14 +256,14 @@ impl<'a> Parser<'a> { match self.parse_unsuffixed_lit() { Ok(lit) => { - return Ok(spanned(lo, self.last_span.hi, ast::NestedMetaItemKind::Literal(lit))) + return Ok(spanned(lo, self.prev_span.hi, ast::NestedMetaItemKind::Literal(lit))) } Err(ref mut err) => self.diagnostic().cancel(err) } match self.parse_meta_item() { Ok(mi) => { - return Ok(spanned(lo, self.last_span.hi, ast::NestedMetaItemKind::MetaItem(mi))) + return Ok(spanned(lo, self.prev_span.hi, ast::NestedMetaItemKind::MetaItem(mi))) } Err(ref mut err) => self.diagnostic().cancel(err) } diff --git a/src/libsyntax/parse/lexer/comments.rs b/src/libsyntax/parse/lexer/comments.rs index 5eb5605ea7..ba83a55ea7 100644 --- a/src/libsyntax/parse/lexer/comments.rs +++ b/src/libsyntax/parse/lexer/comments.rs @@ -24,7 +24,7 @@ use str::char_at; use std::io::Read; use std::usize; -#[derive(Clone, Copy, PartialEq)] +#[derive(Clone, Copy, PartialEq, Debug)] pub enum CommentStyle { /// No code on either side of each line of the comment Isolated, @@ -149,25 +149,24 @@ fn push_blank_line_comment(rdr: &StringReader, comments: &mut Vec) { comments.push(Comment { style: BlankLine, lines: Vec::new(), - pos: rdr.last_pos, + pos: rdr.pos, }); } fn consume_whitespace_counting_blank_lines(rdr: &mut StringReader, comments: &mut Vec) { - while is_pattern_whitespace(rdr.curr) && !rdr.is_eof() { - if rdr.col == CharPos(0) && rdr.curr_is('\n') { + while is_pattern_whitespace(rdr.ch) && !rdr.is_eof() { + if rdr.ch_is('\n') { push_blank_line_comment(rdr, &mut *comments); } rdr.bump(); } } - fn read_shebang_comment(rdr: &mut StringReader, code_to_the_left: bool, comments: &mut Vec) { debug!(">>> shebang comment"); - let p = rdr.last_pos; + let p = rdr.pos; debug!("<<< shebang comment"); comments.push(Comment { style: if code_to_the_left { Trailing } else { Isolated }, @@ -180,9 +179,9 @@ fn read_line_comments(rdr: &mut StringReader, code_to_the_left: bool, comments: &mut Vec) { debug!(">>> line comments"); - let p = rdr.last_pos; + let p = rdr.pos; let mut lines: Vec = Vec::new(); - while rdr.curr_is('/') && rdr.nextch_is('/') { + while rdr.ch_is('/') && rdr.nextch_is('/') { let line = rdr.read_one_line_comment(); debug!("{}", line); // Doc comments are not put in comments. @@ -240,7 +239,7 @@ fn read_block_comment(rdr: &mut StringReader, code_to_the_left: bool, comments: &mut Vec) { debug!(">>> block comment"); - let p = rdr.last_pos; + let p = rdr.pos; let mut lines: Vec = Vec::new(); let col = rdr.col; rdr.bump(); @@ -249,9 +248,9 @@ fn read_block_comment(rdr: &mut StringReader, let mut curr_line = String::from("/*"); // doc-comments are not really comments, they are attributes - if (rdr.curr_is('*') && !rdr.nextch_is('*')) || rdr.curr_is('!') { - while !(rdr.curr_is('*') && rdr.nextch_is('/')) && !rdr.is_eof() { - curr_line.push(rdr.curr.unwrap()); + if (rdr.ch_is('*') && !rdr.nextch_is('*')) || rdr.ch_is('!') { + while !(rdr.ch_is('*') && rdr.nextch_is('/')) && !rdr.is_eof() { + curr_line.push(rdr.ch.unwrap()); rdr.bump(); } if !rdr.is_eof() { @@ -271,19 +270,19 @@ fn read_block_comment(rdr: &mut StringReader, if rdr.is_eof() { panic!(rdr.fatal("unterminated block comment")); } - if rdr.curr_is('\n') { + if rdr.ch_is('\n') { trim_whitespace_prefix_and_push_line(&mut lines, curr_line, col); curr_line = String::new(); rdr.bump(); } else { - curr_line.push(rdr.curr.unwrap()); - if rdr.curr_is('/') && rdr.nextch_is('*') { + curr_line.push(rdr.ch.unwrap()); + if rdr.ch_is('/') && rdr.nextch_is('*') { rdr.bump(); rdr.bump(); curr_line.push('*'); level += 1; } else { - if rdr.curr_is('*') && rdr.nextch_is('/') { + if rdr.ch_is('*') && rdr.nextch_is('/') { rdr.bump(); rdr.bump(); curr_line.push('/'); @@ -305,7 +304,7 @@ fn read_block_comment(rdr: &mut StringReader, Isolated }; rdr.consume_non_eol_whitespace(); - if !rdr.is_eof() && !rdr.curr_is('\n') && lines.len() == 1 { + if !rdr.is_eof() && !rdr.ch_is('\n') && lines.len() == 1 { style = Mixed; } debug!("<<< block comment"); @@ -317,14 +316,22 @@ fn read_block_comment(rdr: &mut StringReader, } -fn consume_comment(rdr: &mut StringReader, code_to_the_left: bool, comments: &mut Vec) { +fn consume_comment(rdr: &mut StringReader, + comments: &mut Vec, + code_to_the_left: &mut bool, + anything_to_the_left: &mut bool) { debug!(">>> consume comment"); - if rdr.curr_is('/') && rdr.nextch_is('/') { - read_line_comments(rdr, code_to_the_left, comments); - } else if rdr.curr_is('/') && rdr.nextch_is('*') { - read_block_comment(rdr, code_to_the_left, comments); - } else if rdr.curr_is('#') && rdr.nextch_is('!') { - read_shebang_comment(rdr, code_to_the_left, comments); + if rdr.ch_is('/') && rdr.nextch_is('/') { + read_line_comments(rdr, *code_to_the_left, comments); + *code_to_the_left = false; + *anything_to_the_left = false; + } else if rdr.ch_is('/') && rdr.nextch_is('*') { + read_block_comment(rdr, *code_to_the_left, comments); + *anything_to_the_left = true; + } else if rdr.ch_is('#') && rdr.nextch_is('!') { + read_shebang_comment(rdr, *code_to_the_left, comments); + *code_to_the_left = false; + *anything_to_the_left = false; } else { panic!(); } @@ -352,24 +359,30 @@ pub fn gather_comments_and_literals(span_diagnostic: &errors::Handler, let mut comments: Vec = Vec::new(); let mut literals: Vec = Vec::new(); - let mut first_read: bool = true; + let mut code_to_the_left = false; // Only code + let mut anything_to_the_left = false; // Code or comments while !rdr.is_eof() { loop { - let mut code_to_the_left = !first_read; + // Eat all the whitespace and count blank lines. rdr.consume_non_eol_whitespace(); - if rdr.curr_is('\n') { - code_to_the_left = false; + if rdr.ch_is('\n') { + if anything_to_the_left { + rdr.bump(); // The line is not blank, do not count. + } consume_whitespace_counting_blank_lines(&mut rdr, &mut comments); + code_to_the_left = false; + anything_to_the_left = false; } - while rdr.peeking_at_comment() { - consume_comment(&mut rdr, code_to_the_left, &mut comments); - consume_whitespace_counting_blank_lines(&mut rdr, &mut comments); + // Eat one comment group + if rdr.peeking_at_comment() { + consume_comment(&mut rdr, &mut comments, + &mut code_to_the_left, &mut anything_to_the_left); + } else { + break } - break; } - - let bstart = rdr.last_pos; + let bstart = rdr.pos; rdr.next_token(); // discard, and look ahead; we're working with internal state let TokenAndSpan { tok, sp } = rdr.peek(); @@ -384,7 +397,8 @@ pub fn gather_comments_and_literals(span_diagnostic: &errors::Handler, } else { debug!("tok: {}", pprust::token_to_string(&tok)); } - first_read = false; + code_to_the_left = true; + anything_to_the_left = true; } (comments, literals) diff --git a/src/libsyntax/parse/lexer/mod.rs b/src/libsyntax/parse/lexer/mod.rs index 6c0e2425d3..cf48c445c8 100644 --- a/src/libsyntax/parse/lexer/mod.rs +++ b/src/libsyntax/parse/lexer/mod.rs @@ -22,7 +22,7 @@ use std::char; use std::mem::replace; use std::rc::Rc; -pub use ext::tt::transcribe::{TtReader, new_tt_reader, new_tt_reader_with_doc_flag}; +pub use ext::tt::transcribe::{TtReader, new_tt_reader}; pub mod comments; mod unicode_chars; @@ -74,16 +74,22 @@ pub struct TokenAndSpan { pub sp: Span, } +impl Default for TokenAndSpan { + fn default() -> Self { + TokenAndSpan { tok: token::Underscore, sp: syntax_pos::DUMMY_SP } + } +} + pub struct StringReader<'a> { pub span_diagnostic: &'a Handler, /// The absolute offset within the codemap of the next character to read + pub next_pos: BytePos, + /// The absolute offset within the codemap of the current character pub pos: BytePos, - /// The absolute offset within the codemap of the last character read(curr) - pub last_pos: BytePos, /// The column of the next character to read pub col: CharPos, - /// The last character to be read - pub curr: Option, + /// The current character (which has been read from self.pos) + pub ch: Option, pub filemap: Rc, /// If Some, stop reading the source at this position (inclusive). pub terminator: Option, @@ -102,12 +108,12 @@ pub struct StringReader<'a> { impl<'a> Reader for StringReader<'a> { fn is_eof(&self) -> bool { - if self.curr.is_none() { + if self.ch.is_none() { return true; } match self.terminator { - Some(t) => self.pos > t, + Some(t) => self.next_pos > t, None => false, } } @@ -144,7 +150,7 @@ impl<'a> Reader for StringReader<'a> { impl<'a> Reader for TtReader<'a> { fn is_eof(&self) -> bool { - self.cur_tok == token::Eof + self.peek().tok == token::Eof } fn try_next_token(&mut self) -> Result { assert!(self.fatal_errs.is_empty()); @@ -173,7 +179,7 @@ impl<'a> Reader for TtReader<'a> { } impl<'a> StringReader<'a> { - /// For comments.rs, which hackily pokes into pos and curr + /// For comments.rs, which hackily pokes into next_pos and ch pub fn new_raw<'b>(span_diagnostic: &'b Handler, filemap: Rc) -> StringReader<'b> { @@ -195,10 +201,10 @@ impl<'a> StringReader<'a> { StringReader { span_diagnostic: span_diagnostic, + next_pos: filemap.start_pos, pos: filemap.start_pos, - last_pos: filemap.start_pos, col: CharPos(0), - curr: Some('\n'), + ch: Some('\n'), filemap: filemap, terminator: None, save_new_lines: true, @@ -221,8 +227,8 @@ impl<'a> StringReader<'a> { sr } - pub fn curr_is(&self, c: char) -> bool { - self.curr == Some(c) + pub fn ch_is(&self, c: char) -> bool { + self.ch == Some(c) } /// Report a fatal lexical error with a given span. @@ -317,9 +323,9 @@ impl<'a> StringReader<'a> { self.peek_tok = token::Eof; self.peek_span = syntax_pos::mk_sp(self.filemap.end_pos, self.filemap.end_pos); } else { - let start_bytepos = self.last_pos; + let start_bytepos = self.pos; self.peek_tok = self.next_token_inner()?; - self.peek_span = syntax_pos::mk_sp(start_bytepos, self.last_pos); + self.peek_span = syntax_pos::mk_sp(start_bytepos, self.pos); }; } } @@ -331,19 +337,19 @@ impl<'a> StringReader<'a> { } /// Calls `f` with a string slice of the source text spanning from `start` - /// up to but excluding `self.last_pos`, meaning the slice does not include - /// the character `self.curr`. + /// up to but excluding `self.pos`, meaning the slice does not include + /// the character `self.ch`. pub fn with_str_from(&self, start: BytePos, f: F) -> T where F: FnOnce(&str) -> T { - self.with_str_from_to(start, self.last_pos, f) + self.with_str_from_to(start, self.pos, f) } /// Create a Name from a given offset to the current offset, each /// adjusted 1 towards each other (assumes that on either side there is a /// single-byte delimiter). pub fn name_from(&self, start: BytePos) -> ast::Name { - debug!("taking an ident from {:?} to {:?}", start, self.last_pos); + debug!("taking an ident from {:?} to {:?}", start, self.pos); self.with_str_from(start, token::intern) } @@ -414,34 +420,35 @@ impl<'a> StringReader<'a> { /// Advance the StringReader by one character. If a newline is /// discovered, add it to the FileMap's list of line start offsets. pub fn bump(&mut self) { - self.last_pos = self.pos; - let current_byte_offset = self.byte_offset(self.pos).to_usize(); - if current_byte_offset < self.source_text.len() { - assert!(self.curr.is_some()); - let last_char = self.curr.unwrap(); - let ch = char_at(&self.source_text, current_byte_offset); - let next = current_byte_offset + ch.len_utf8(); - let byte_offset_diff = next - current_byte_offset; - self.pos = self.pos + Pos::from_usize(byte_offset_diff); - self.curr = Some(ch); - self.col = self.col + CharPos(1); - if last_char == '\n' { + let new_pos = self.next_pos; + let new_byte_offset = self.byte_offset(new_pos).to_usize(); + if new_byte_offset < self.source_text.len() { + let old_ch_is_newline = self.ch.unwrap() == '\n'; + let new_ch = char_at(&self.source_text, new_byte_offset); + let new_ch_len = new_ch.len_utf8(); + + self.ch = Some(new_ch); + self.pos = new_pos; + self.next_pos = new_pos + Pos::from_usize(new_ch_len); + if old_ch_is_newline { if self.save_new_lines { - self.filemap.next_line(self.last_pos); + self.filemap.next_line(self.pos); } self.col = CharPos(0); + } else { + self.col = self.col + CharPos(1); } - - if byte_offset_diff > 1 { - self.filemap.record_multibyte_char(self.last_pos, byte_offset_diff); + if new_ch_len > 1 { + self.filemap.record_multibyte_char(self.pos, new_ch_len); } } else { - self.curr = None; + self.ch = None; + self.pos = new_pos; } } pub fn nextch(&self) -> Option { - let offset = self.byte_offset(self.pos).to_usize(); + let offset = self.byte_offset(self.next_pos).to_usize(); if offset < self.source_text.len() { Some(char_at(&self.source_text, offset)) } else { @@ -454,7 +461,7 @@ impl<'a> StringReader<'a> { } pub fn nextnextch(&self) -> Option { - let offset = self.byte_offset(self.pos).to_usize(); + let offset = self.byte_offset(self.next_pos).to_usize(); let s = &self.source_text[..]; if offset >= s.len() { return None; @@ -473,11 +480,11 @@ impl<'a> StringReader<'a> { /// Eats *, if possible. fn scan_optional_raw_name(&mut self) -> Option { - if !ident_start(self.curr) { + if !ident_start(self.ch) { return None; } - let start = self.last_pos; - while ident_continue(self.curr) { + let start = self.pos; + while ident_continue(self.ch) { self.bump(); } @@ -490,41 +497,37 @@ impl<'a> StringReader<'a> { }) } - /// PRECONDITION: self.curr is not whitespace + /// PRECONDITION: self.ch is not whitespace /// Eats any kind of comment. fn scan_comment(&mut self) -> Option { - if let Some(c) = self.curr { + if let Some(c) = self.ch { if c.is_whitespace() { - self.span_diagnostic.span_err(syntax_pos::mk_sp(self.last_pos, self.last_pos), + self.span_diagnostic.span_err(syntax_pos::mk_sp(self.pos, self.pos), "called consume_any_line_comment, but there \ was whitespace"); } } - if self.curr_is('/') { + if self.ch_is('/') { match self.nextch() { Some('/') => { self.bump(); self.bump(); // line comments starting with "///" or "//!" are doc-comments - let doc_comment = self.curr_is('/') || self.curr_is('!'); - let start_bpos = if doc_comment { - self.pos - BytePos(3) - } else { - self.last_pos - BytePos(2) - }; + let doc_comment = self.ch_is('/') || self.ch_is('!'); + let start_bpos = self.pos - BytePos(2); while !self.is_eof() { - match self.curr.unwrap() { + match self.ch.unwrap() { '\n' => break, '\r' => { if self.nextch_is('\n') { // CRLF break; } else if doc_comment { - self.err_span_(self.last_pos, - self.pos, + self.err_span_(self.pos, + self.next_pos, "bare CR not allowed in doc-comment"); } } @@ -544,13 +547,13 @@ impl<'a> StringReader<'a> { Some(TokenAndSpan { tok: tok, - sp: syntax_pos::mk_sp(start_bpos, self.last_pos), + sp: syntax_pos::mk_sp(start_bpos, self.pos), }) }) } else { Some(TokenAndSpan { tok: token::Comment, - sp: syntax_pos::mk_sp(start_bpos, self.last_pos), + sp: syntax_pos::mk_sp(start_bpos, self.pos), }) }; } @@ -561,7 +564,7 @@ impl<'a> StringReader<'a> { } _ => None, } - } else if self.curr_is('#') { + } else if self.ch_is('#') { if self.nextch_is('!') { // Parse an inner attribute. @@ -573,17 +576,17 @@ impl<'a> StringReader<'a> { // we're at the beginning of the file... let cmap = CodeMap::new(); cmap.files.borrow_mut().push(self.filemap.clone()); - let loc = cmap.lookup_char_pos_adj(self.last_pos); + let loc = cmap.lookup_char_pos_adj(self.pos); debug!("Skipping a shebang"); if loc.line == 1 && loc.col == CharPos(0) { // FIXME: Add shebang "token", return it - let start = self.last_pos; - while !self.curr_is('\n') && !self.is_eof() { + let start = self.pos; + while !self.ch_is('\n') && !self.is_eof() { self.bump(); } return Some(TokenAndSpan { tok: token::Shebang(self.name_from(start)), - sp: syntax_pos::mk_sp(start, self.last_pos), + sp: syntax_pos::mk_sp(start, self.pos), }); } } @@ -596,7 +599,7 @@ impl<'a> StringReader<'a> { /// If there is whitespace, shebang, or a comment, scan it. Otherwise, /// return None. fn scan_whitespace_or_comment(&mut self) -> Option { - match self.curr.unwrap_or('\0') { + match self.ch.unwrap_or('\0') { // # to handle shebang at start of file -- this is the entry point // for skipping over all "junk" '/' | '#' => { @@ -605,13 +608,13 @@ impl<'a> StringReader<'a> { c }, c if is_pattern_whitespace(Some(c)) => { - let start_bpos = self.last_pos; - while is_pattern_whitespace(self.curr) { + let start_bpos = self.pos; + while is_pattern_whitespace(self.ch) { self.bump(); } let c = Some(TokenAndSpan { tok: token::Whitespace, - sp: syntax_pos::mk_sp(start_bpos, self.last_pos), + sp: syntax_pos::mk_sp(start_bpos, self.pos), }); debug!("scanning whitespace: {:?}", c); c @@ -623,8 +626,8 @@ impl<'a> StringReader<'a> { /// Might return a sugared-doc-attr fn scan_block_comment(&mut self) -> Option { // block comments starting with "/**" or "/*!" are doc-comments - let is_doc_comment = self.curr_is('*') || self.curr_is('!'); - let start_bpos = self.last_pos - BytePos(2); + let is_doc_comment = self.ch_is('*') || self.ch_is('!'); + let start_bpos = self.pos - BytePos(2); let mut level: isize = 1; let mut has_cr = false; @@ -635,10 +638,10 @@ impl<'a> StringReader<'a> { } else { "unterminated block comment" }; - let last_bpos = self.last_pos; + let last_bpos = self.pos; panic!(self.fatal_span_(start_bpos, last_bpos, msg)); } - let n = self.curr.unwrap(); + let n = self.ch.unwrap(); match n { '/' if self.nextch_is('*') => { level += 1; @@ -673,7 +676,7 @@ impl<'a> StringReader<'a> { Some(TokenAndSpan { tok: tok, - sp: syntax_pos::mk_sp(start_bpos, self.last_pos), + sp: syntax_pos::mk_sp(start_bpos, self.pos), }) }) } @@ -688,7 +691,7 @@ impl<'a> StringReader<'a> { assert!(real_radix <= scan_radix); let mut len = 0; loop { - let c = self.curr; + let c = self.ch; if c == Some('_') { debug!("skipping a _"); self.bump(); @@ -700,8 +703,8 @@ impl<'a> StringReader<'a> { // check that the hypothetical digit is actually // in range for the true radix if c.unwrap().to_digit(real_radix).is_none() { - self.err_span_(self.last_pos, - self.pos, + self.err_span_(self.pos, + self.next_pos, &format!("invalid digit for a base {} literal", real_radix)); } len += 1; @@ -716,12 +719,12 @@ impl<'a> StringReader<'a> { fn scan_number(&mut self, c: char) -> token::Lit { let num_digits; let mut base = 10; - let start_bpos = self.last_pos; + let start_bpos = self.pos; self.bump(); if c == '0' { - match self.curr.unwrap_or('\0') { + match self.ch.unwrap_or('\0') { 'b' => { self.bump(); base = 2; @@ -753,7 +756,7 @@ impl<'a> StringReader<'a> { if num_digits == 0 { self.err_span_(start_bpos, - self.last_pos, + self.pos, "no valid digits found for number"); return token::Integer(token::intern("0")); } @@ -761,26 +764,26 @@ impl<'a> StringReader<'a> { // might be a float, but don't be greedy if this is actually an // integer literal followed by field/method access or a range pattern // (`0..2` and `12.foo()`) - if self.curr_is('.') && !self.nextch_is('.') && + if self.ch_is('.') && !self.nextch_is('.') && !self.nextch() .unwrap_or('\0') .is_xid_start() { // might have stuff after the ., and if it does, it needs to start // with a number self.bump(); - if self.curr.unwrap_or('\0').is_digit(10) { + if self.ch.unwrap_or('\0').is_digit(10) { self.scan_digits(10, 10); self.scan_float_exponent(); } - let last_pos = self.last_pos; - self.check_float_base(start_bpos, last_pos, base); + let pos = self.pos; + self.check_float_base(start_bpos, pos, base); return token::Float(self.name_from(start_bpos)); } else { // it might be a float if it has an exponent - if self.curr_is('e') || self.curr_is('E') { + if self.ch_is('e') || self.ch_is('E') { self.scan_float_exponent(); - let last_pos = self.last_pos; - self.check_float_base(start_bpos, last_pos, base); + let pos = self.pos; + self.check_float_base(start_bpos, pos, base); return token::Float(self.name_from(start_bpos)); } // but we certainly have an integer! @@ -792,30 +795,30 @@ impl<'a> StringReader<'a> { /// error if too many or too few digits are encountered. fn scan_hex_digits(&mut self, n_digits: usize, delim: char, below_0x7f_only: bool) -> bool { debug!("scanning {} digits until {:?}", n_digits, delim); - let start_bpos = self.last_pos; + let start_bpos = self.pos; let mut accum_int = 0; let mut valid = true; for _ in 0..n_digits { if self.is_eof() { - let last_bpos = self.last_pos; + let last_bpos = self.pos; panic!(self.fatal_span_(start_bpos, last_bpos, "unterminated numeric character escape")); } - if self.curr_is(delim) { - let last_bpos = self.last_pos; + if self.ch_is(delim) { + let last_bpos = self.pos; self.err_span_(start_bpos, last_bpos, "numeric character escape is too short"); valid = false; break; } - let c = self.curr.unwrap_or('\x00'); + let c = self.ch.unwrap_or('\x00'); accum_int *= 16; accum_int += c.to_digit(16).unwrap_or_else(|| { - self.err_span_char(self.last_pos, - self.pos, + self.err_span_char(self.pos, + self.next_pos, "invalid character in numeric character escape", c); @@ -827,7 +830,7 @@ impl<'a> StringReader<'a> { if below_0x7f_only && accum_int >= 0x80 { self.err_span_(start_bpos, - self.last_pos, + self.pos, "this form of character escape may only be used with characters in \ the range [\\x00-\\x7f]"); valid = false; @@ -836,7 +839,7 @@ impl<'a> StringReader<'a> { match char::from_u32(accum_int) { Some(_) => valid, None => { - let last_bpos = self.last_pos; + let last_bpos = self.pos; self.err_span_(start_bpos, last_bpos, "invalid numeric character escape"); false } @@ -857,8 +860,8 @@ impl<'a> StringReader<'a> { match first_source_char { '\\' => { // '\X' for some X must be a character constant: - let escaped = self.curr; - let escaped_pos = self.last_pos; + let escaped = self.ch; + let escaped_pos = self.pos; self.bump(); match escaped { None => {} // EOF here is an error that will be checked later. @@ -867,10 +870,10 @@ impl<'a> StringReader<'a> { 'n' | 'r' | 't' | '\\' | '\'' | '"' | '0' => true, 'x' => self.scan_byte_escape(delim, !ascii_only), 'u' => { - let valid = if self.curr_is('{') { + let valid = if self.ch_is('{') { self.scan_unicode_escape(delim) && !ascii_only } else { - let span = syntax_pos::mk_sp(start, self.last_pos); + let span = syntax_pos::mk_sp(start, self.pos); self.span_diagnostic .struct_span_err(span, "incorrect unicode escape sequence") .span_help(span, @@ -881,7 +884,7 @@ impl<'a> StringReader<'a> { }; if ascii_only { self.err_span_(start, - self.last_pos, + self.pos, "unicode escape sequences cannot be used as a \ byte or in a byte string"); } @@ -892,14 +895,14 @@ impl<'a> StringReader<'a> { self.consume_whitespace(); true } - '\r' if delim == '"' && self.curr_is('\n') => { + '\r' if delim == '"' && self.ch_is('\n') => { self.consume_whitespace(); true } c => { - let last_pos = self.last_pos; + let pos = self.pos; let mut err = self.struct_err_span_char(escaped_pos, - last_pos, + pos, if ascii_only { "unknown byte escape" } else { @@ -908,13 +911,13 @@ impl<'a> StringReader<'a> { }, c); if e == '\r' { - err.span_help(syntax_pos::mk_sp(escaped_pos, last_pos), + err.span_help(syntax_pos::mk_sp(escaped_pos, pos), "this is an isolated carriage return; consider \ checking your editor and version control \ settings"); } if (e == '{' || e == '}') && !ascii_only { - err.span_help(syntax_pos::mk_sp(escaped_pos, last_pos), + err.span_help(syntax_pos::mk_sp(escaped_pos, pos), "if used in a formatting string, curly braces \ are escaped with `{{` and `}}`"); } @@ -926,9 +929,9 @@ impl<'a> StringReader<'a> { } } '\t' | '\n' | '\r' | '\'' if delim == '\'' => { - let last_pos = self.last_pos; + let pos = self.pos; self.err_span_char(start, - last_pos, + pos, if ascii_only { "byte constant must be escaped" } else { @@ -938,21 +941,21 @@ impl<'a> StringReader<'a> { return false; } '\r' => { - if self.curr_is('\n') { + if self.ch_is('\n') { self.bump(); return true; } else { self.err_span_(start, - self.last_pos, + self.pos, "bare CR not allowed in string, use \\r instead"); return false; } } _ => { if ascii_only && first_source_char > '\x7F' { - let last_pos = self.last_pos; + let pos = self.pos; self.err_span_(start, - last_pos, + pos, "byte constant must be ASCII. Use a \\xHH escape for a \ non-ASCII byte"); return false; @@ -968,29 +971,29 @@ impl<'a> StringReader<'a> { /// will read at least one digit, and up to 6, and pass over the }. fn scan_unicode_escape(&mut self, delim: char) -> bool { self.bump(); // past the { - let start_bpos = self.last_pos; + let start_bpos = self.pos; let mut count = 0; let mut accum_int = 0; let mut valid = true; - while !self.curr_is('}') && count <= 6 { - let c = match self.curr { + while !self.ch_is('}') && count <= 6 { + let c = match self.ch { Some(c) => c, None => { panic!(self.fatal_span_(start_bpos, - self.last_pos, + self.pos, "unterminated unicode escape (found EOF)")); } }; accum_int *= 16; accum_int += c.to_digit(16).unwrap_or_else(|| { if c == delim { - panic!(self.fatal_span_(self.last_pos, - self.pos, + panic!(self.fatal_span_(self.pos, + self.next_pos, "unterminated unicode escape (needed a `}`)")); } else { - self.err_span_char(self.last_pos, - self.pos, + self.err_span_char(self.pos, + self.next_pos, "invalid character in unicode escape", c); } @@ -1003,14 +1006,14 @@ impl<'a> StringReader<'a> { if count > 6 { self.err_span_(start_bpos, - self.last_pos, + self.pos, "overlong unicode escape (can have at most 6 hex digits)"); valid = false; } if valid && (char::from_u32(accum_int).is_none() || count == 0) { self.err_span_(start_bpos, - self.last_pos, + self.pos, "invalid unicode character escape"); valid = false; } @@ -1021,14 +1024,14 @@ impl<'a> StringReader<'a> { /// Scan over a float exponent. fn scan_float_exponent(&mut self) { - if self.curr_is('e') || self.curr_is('E') { + if self.ch_is('e') || self.ch_is('E') { self.bump(); - if self.curr_is('-') || self.curr_is('+') { + if self.ch_is('-') || self.ch_is('+') { self.bump(); } if self.scan_digits(10, 10) == 0 { - self.err_span_(self.last_pos, - self.pos, + self.err_span_(self.pos, + self.next_pos, "expected at least one digit in exponent") } } @@ -1059,7 +1062,7 @@ impl<'a> StringReader<'a> { fn binop(&mut self, op: token::BinOpToken) -> token::Token { self.bump(); - if self.curr_is('=') { + if self.ch_is('=') { self.bump(); return token::BinOpEq(op); } else { @@ -1070,7 +1073,7 @@ impl<'a> StringReader<'a> { /// Return the next token from the string, advances the input past that /// token, and updates the interner fn next_token_inner(&mut self) -> Result { - let c = self.curr; + let c = self.ch; if ident_start(c) && match (c.unwrap(), self.nextch(), self.nextnextch()) { // Note: r as in r" or r#" is part of a raw string literal, @@ -1084,8 +1087,8 @@ impl<'a> StringReader<'a> { ('b', Some('r'), Some('#')) => false, _ => true, } { - let start = self.last_pos; - while ident_continue(self.curr) { + let start = self.pos; + while ident_continue(self.ch) { self.bump(); } @@ -1118,9 +1121,9 @@ impl<'a> StringReader<'a> { } '.' => { self.bump(); - return if self.curr_is('.') { + return if self.ch_is('.') { self.bump(); - if self.curr_is('.') { + if self.ch_is('.') { self.bump(); Ok(token::DotDotDot) } else { @@ -1172,7 +1175,7 @@ impl<'a> StringReader<'a> { } ':' => { self.bump(); - if self.curr_is(':') { + if self.ch_is(':') { self.bump(); return Ok(token::ModSep); } else { @@ -1188,10 +1191,10 @@ impl<'a> StringReader<'a> { // Multi-byte tokens. '=' => { self.bump(); - if self.curr_is('=') { + if self.ch_is('=') { self.bump(); return Ok(token::EqEq); - } else if self.curr_is('>') { + } else if self.ch_is('>') { self.bump(); return Ok(token::FatArrow); } else { @@ -1200,7 +1203,7 @@ impl<'a> StringReader<'a> { } '!' => { self.bump(); - if self.curr_is('=') { + if self.ch_is('=') { self.bump(); return Ok(token::Ne); } else { @@ -1209,7 +1212,7 @@ impl<'a> StringReader<'a> { } '<' => { self.bump(); - match self.curr.unwrap_or('\x00') { + match self.ch.unwrap_or('\x00') { '=' => { self.bump(); return Ok(token::Le); @@ -1219,7 +1222,7 @@ impl<'a> StringReader<'a> { } '-' => { self.bump(); - match self.curr.unwrap_or('\x00') { + match self.ch.unwrap_or('\x00') { _ => { return Ok(token::LArrow); } @@ -1232,7 +1235,7 @@ impl<'a> StringReader<'a> { } '>' => { self.bump(); - match self.curr.unwrap_or('\x00') { + match self.ch.unwrap_or('\x00') { '=' => { self.bump(); return Ok(token::Ge); @@ -1247,25 +1250,25 @@ impl<'a> StringReader<'a> { } '\'' => { // Either a character constant 'a' OR a lifetime name 'abc - let start_with_quote = self.last_pos; + let start_with_quote = self.pos; self.bump(); - let start = self.last_pos; + let start = self.pos; // the eof will be picked up by the final `'` check below - let c2 = self.curr.unwrap_or('\x00'); + let c2 = self.ch.unwrap_or('\x00'); self.bump(); // If the character is an ident start not followed by another single // quote, then this is a lifetime name: - if ident_start(Some(c2)) && !self.curr_is('\'') { - while ident_continue(self.curr) { + if ident_start(Some(c2)) && !self.ch_is('\'') { + while ident_continue(self.ch) { self.bump(); } // lifetimes shouldn't end with a single quote // if we find one, then this is an invalid character literal - if self.curr_is('\'') { + if self.ch_is('\'') { panic!(self.fatal_span_verbose( - start_with_quote, self.pos, + start_with_quote, self.next_pos, String::from("character literal may only contain one codepoint"))); } @@ -1283,7 +1286,7 @@ impl<'a> StringReader<'a> { str_to_ident(lifetime_name) }); let keyword_checking_token = &token::Ident(keyword_checking_ident); - let last_bpos = self.last_pos; + let last_bpos = self.pos; if keyword_checking_token.is_any_keyword() && !keyword_checking_token.is_keyword(keywords::Static) { self.err_span_(start, last_bpos, "lifetimes cannot use keyword names"); @@ -1298,9 +1301,9 @@ impl<'a> StringReader<'a> { false, '\''); - if !self.curr_is('\'') { + if !self.ch_is('\'') { panic!(self.fatal_span_verbose( - start_with_quote, self.last_pos, + start_with_quote, self.pos, String::from("character literal may only contain one codepoint"))); } @@ -1309,13 +1312,13 @@ impl<'a> StringReader<'a> { } else { token::intern("0") }; - self.bump(); // advance curr past token + self.bump(); // advance ch past token let suffix = self.scan_optional_raw_name(); return Ok(token::Literal(token::Char(id), suffix)); } 'b' => { self.bump(); - let lit = match self.curr { + let lit = match self.ch { Some('\'') => self.scan_byte(), Some('"') => self.scan_byte_string(), Some('r') => self.scan_raw_byte_string(), @@ -1325,19 +1328,19 @@ impl<'a> StringReader<'a> { return Ok(token::Literal(lit, suffix)); } '"' => { - let start_bpos = self.last_pos; + let start_bpos = self.pos; let mut valid = true; self.bump(); - while !self.curr_is('"') { + while !self.ch_is('"') { if self.is_eof() { - let last_bpos = self.last_pos; + let last_bpos = self.pos; panic!(self.fatal_span_(start_bpos, last_bpos, "unterminated double quote string")); } - let ch_start = self.last_pos; - let ch = self.curr.unwrap(); + let ch_start = self.pos; + let ch = self.ch.unwrap(); self.bump(); valid &= self.scan_char_or_byte(ch_start, ch, @@ -1356,20 +1359,20 @@ impl<'a> StringReader<'a> { return Ok(token::Literal(token::Str_(id), suffix)); } 'r' => { - let start_bpos = self.last_pos; + let start_bpos = self.pos; self.bump(); let mut hash_count = 0; - while self.curr_is('#') { + while self.ch_is('#') { self.bump(); hash_count += 1; } if self.is_eof() { - let last_bpos = self.last_pos; + let last_bpos = self.pos; panic!(self.fatal_span_(start_bpos, last_bpos, "unterminated raw string")); - } else if !self.curr_is('"') { - let last_bpos = self.last_pos; - let curr_char = self.curr.unwrap(); + } else if !self.ch_is('"') { + let last_bpos = self.pos; + let curr_char = self.ch.unwrap(); panic!(self.fatal_span_char(start_bpos, last_bpos, "found invalid character; only `#` is allowed \ @@ -1377,27 +1380,27 @@ impl<'a> StringReader<'a> { curr_char)); } self.bump(); - let content_start_bpos = self.last_pos; + let content_start_bpos = self.pos; let mut content_end_bpos; let mut valid = true; 'outer: loop { if self.is_eof() { - let last_bpos = self.last_pos; + let last_bpos = self.pos; panic!(self.fatal_span_(start_bpos, last_bpos, "unterminated raw string")); } - // if self.curr_is('"') { - // content_end_bpos = self.last_pos; + // if self.ch_is('"') { + // content_end_bpos = self.pos; // for _ in 0..hash_count { // self.bump(); - // if !self.curr_is('#') { + // if !self.ch_is('#') { // continue 'outer; - let c = self.curr.unwrap(); + let c = self.ch.unwrap(); match c { '"' => { - content_end_bpos = self.last_pos; + content_end_bpos = self.pos; for _ in 0..hash_count { self.bump(); - if !self.curr_is('#') { + if !self.ch_is('#') { continue 'outer; } } @@ -1405,7 +1408,7 @@ impl<'a> StringReader<'a> { } '\r' => { if !self.nextch_is('\n') { - let last_bpos = self.last_pos; + let last_bpos = self.pos; self.err_span_(start_bpos, last_bpos, "bare CR not allowed in raw string, use \\r \ @@ -1472,8 +1475,8 @@ impl<'a> StringReader<'a> { return Ok(self.binop(token::Percent)); } c => { - let last_bpos = self.last_pos; - let bpos = self.pos; + let last_bpos = self.pos; + let bpos = self.next_pos; let mut err = self.struct_fatal_span_char(last_bpos, bpos, "unknown start of token", @@ -1486,18 +1489,18 @@ impl<'a> StringReader<'a> { } fn consume_whitespace(&mut self) { - while is_pattern_whitespace(self.curr) && !self.is_eof() { + while is_pattern_whitespace(self.ch) && !self.is_eof() { self.bump(); } } fn read_to_eol(&mut self) -> String { let mut val = String::new(); - while !self.curr_is('\n') && !self.is_eof() { - val.push(self.curr.unwrap()); + while !self.ch_is('\n') && !self.is_eof() { + val.push(self.ch.unwrap()); self.bump(); } - if self.curr_is('\n') { + if self.ch_is('\n') { self.bump(); } return val; @@ -1511,23 +1514,23 @@ impl<'a> StringReader<'a> { } fn consume_non_eol_whitespace(&mut self) { - while is_pattern_whitespace(self.curr) && !self.curr_is('\n') && !self.is_eof() { + while is_pattern_whitespace(self.ch) && !self.ch_is('\n') && !self.is_eof() { self.bump(); } } fn peeking_at_comment(&self) -> bool { - (self.curr_is('/') && self.nextch_is('/')) || (self.curr_is('/') && self.nextch_is('*')) || + (self.ch_is('/') && self.nextch_is('/')) || (self.ch_is('/') && self.nextch_is('*')) || // consider shebangs comments, but not inner attributes - (self.curr_is('#') && self.nextch_is('!') && !self.nextnextch_is('[')) + (self.ch_is('#') && self.nextch_is('!') && !self.nextnextch_is('[')) } fn scan_byte(&mut self) -> token::Lit { self.bump(); - let start = self.last_pos; + let start = self.pos; // the eof will be picked up by the final `'` check below - let c2 = self.curr.unwrap_or('\x00'); + let c2 = self.ch.unwrap_or('\x00'); self.bump(); let valid = self.scan_char_or_byte(start, @@ -1535,13 +1538,13 @@ impl<'a> StringReader<'a> { // ascii_only = true, '\''); - if !self.curr_is('\'') { + if !self.ch_is('\'') { // Byte offsetting here is okay because the // character before position `start` are an // ascii single quote and ascii 'b'. - let last_pos = self.last_pos; + let pos = self.pos; panic!(self.fatal_span_verbose(start - BytePos(2), - last_pos, + pos, "unterminated byte constant".to_string())); } @@ -1550,7 +1553,7 @@ impl<'a> StringReader<'a> { } else { token::intern("?") }; - self.bump(); // advance curr past token + self.bump(); // advance ch past token return token::Byte(id); } @@ -1560,17 +1563,17 @@ impl<'a> StringReader<'a> { fn scan_byte_string(&mut self) -> token::Lit { self.bump(); - let start = self.last_pos; + let start = self.pos; let mut valid = true; - while !self.curr_is('"') { + while !self.ch_is('"') { if self.is_eof() { - let last_pos = self.last_pos; - panic!(self.fatal_span_(start, last_pos, "unterminated double quote byte string")); + let pos = self.pos; + panic!(self.fatal_span_(start, pos, "unterminated double quote byte string")); } - let ch_start = self.last_pos; - let ch = self.curr.unwrap(); + let ch_start = self.pos; + let ch = self.ch.unwrap(); self.bump(); valid &= self.scan_char_or_byte(ch_start, ch, @@ -1588,40 +1591,40 @@ impl<'a> StringReader<'a> { } fn scan_raw_byte_string(&mut self) -> token::Lit { - let start_bpos = self.last_pos; + let start_bpos = self.pos; self.bump(); let mut hash_count = 0; - while self.curr_is('#') { + while self.ch_is('#') { self.bump(); hash_count += 1; } if self.is_eof() { - let last_pos = self.last_pos; - panic!(self.fatal_span_(start_bpos, last_pos, "unterminated raw string")); - } else if !self.curr_is('"') { - let last_pos = self.last_pos; - let ch = self.curr.unwrap(); + let pos = self.pos; + panic!(self.fatal_span_(start_bpos, pos, "unterminated raw string")); + } else if !self.ch_is('"') { + let pos = self.pos; + let ch = self.ch.unwrap(); panic!(self.fatal_span_char(start_bpos, - last_pos, + pos, "found invalid character; only `#` is allowed in raw \ string delimitation", ch)); } self.bump(); - let content_start_bpos = self.last_pos; + let content_start_bpos = self.pos; let mut content_end_bpos; 'outer: loop { - match self.curr { + match self.ch { None => { - let last_pos = self.last_pos; - panic!(self.fatal_span_(start_bpos, last_pos, "unterminated raw string")) + let pos = self.pos; + panic!(self.fatal_span_(start_bpos, pos, "unterminated raw string")) } Some('"') => { - content_end_bpos = self.last_pos; + content_end_bpos = self.pos; for _ in 0..hash_count { self.bump(); - if !self.curr_is('#') { + if !self.ch_is('#') { continue 'outer; } } @@ -1629,8 +1632,8 @@ impl<'a> StringReader<'a> { } Some(c) => { if c > '\x7F' { - let last_pos = self.last_pos; - self.err_span_char(last_pos, last_pos, "raw byte string must be ASCII", c); + let pos = self.pos; + self.err_span_char(pos, pos, "raw byte string must be ASCII", c); } } } @@ -1744,7 +1747,7 @@ mod tests { assert_eq!(tok1, tok2); assert_eq!(string_reader.next_token().tok, token::Whitespace); // the 'main' id is already read: - assert_eq!(string_reader.last_pos.clone(), BytePos(28)); + assert_eq!(string_reader.pos.clone(), BytePos(28)); // read another token: let tok3 = string_reader.next_token(); let tok4 = TokenAndSpan { @@ -1757,7 +1760,7 @@ mod tests { }; assert_eq!(tok3, tok4); // the lparen is already read: - assert_eq!(string_reader.last_pos.clone(), BytePos(29)) + assert_eq!(string_reader.pos.clone(), BytePos(29)) } // check that the given reader produces the desired stream diff --git a/src/libsyntax/parse/lexer/unicode_chars.rs b/src/libsyntax/parse/lexer/unicode_chars.rs index dab97d1d5a..1e08b20b7e 100644 --- a/src/libsyntax/parse/lexer/unicode_chars.rs +++ b/src/libsyntax/parse/lexer/unicode_chars.rs @@ -234,7 +234,7 @@ pub fn check_for_substitution<'a>(reader: &StringReader<'a>, .iter() .find(|&&(c, _, _)| c == ch) .map(|&(_, u_name, ascii_char)| { - let span = make_span(reader.last_pos, reader.pos); + let span = make_span(reader.pos, reader.next_pos); match ASCII_ARRAY.iter().find(|&&(c, _)| c == ascii_char) { Some(&(ascii_char, ascii_name)) => { let msg = diff --git a/src/libsyntax/parse/mod.rs b/src/libsyntax/parse/mod.rs index 1e286c143d..12408c7d3c 100644 --- a/src/libsyntax/parse/mod.rs +++ b/src/libsyntax/parse/mod.rs @@ -10,7 +10,7 @@ //! The main parser interface -use ast; +use ast::{self, CrateConfig}; use codemap::CodeMap; use syntax_pos::{self, Span, FileMap}; use errors::{Handler, ColorConfig, DiagnosticBuilder}; @@ -44,13 +44,14 @@ pub mod obsolete; pub struct ParseSess { pub span_diagnostic: Handler, // better be the same as the one in the reader! pub unstable_features: UnstableFeatures, + pub config: CrateConfig, /// Used to determine and report recursive mod inclusions included_mod_stack: RefCell>, code_map: Rc, } impl ParseSess { - pub fn new() -> ParseSess { + pub fn new() -> Self { let cm = Rc::new(CodeMap::new()); let handler = Handler::with_tty_emitter(ColorConfig::Auto, true, @@ -63,6 +64,7 @@ impl ParseSess { ParseSess { span_diagnostic: handler, unstable_features: UnstableFeatures::from_environment(), + config: Vec::new(), included_mod_stack: RefCell::new(vec![]), code_map: code_map } @@ -78,146 +80,90 @@ impl ParseSess { // uses a HOF to parse anything, and includes file and // source_str. -pub fn parse_crate_from_file<'a>(input: &Path, - cfg: ast::CrateConfig, - sess: &'a ParseSess) - -> PResult<'a, ast::Crate> { - let mut parser = new_parser_from_file(sess, cfg, input); +pub fn parse_crate_from_file<'a>(input: &Path, sess: &'a ParseSess) -> PResult<'a, ast::Crate> { + let mut parser = new_parser_from_file(sess, input); parser.parse_crate_mod() } -pub fn parse_crate_attrs_from_file<'a>(input: &Path, - cfg: ast::CrateConfig, - sess: &'a ParseSess) +pub fn parse_crate_attrs_from_file<'a>(input: &Path, sess: &'a ParseSess) -> PResult<'a, Vec> { - let mut parser = new_parser_from_file(sess, cfg, input); + let mut parser = new_parser_from_file(sess, input); parser.parse_inner_attributes() } -pub fn parse_crate_from_source_str<'a>(name: String, - source: String, - cfg: ast::CrateConfig, - sess: &'a ParseSess) +pub fn parse_crate_from_source_str<'a>(name: String, source: String, sess: &'a ParseSess) -> PResult<'a, ast::Crate> { - let mut p = new_parser_from_source_str(sess, - cfg, - name, - source); - p.parse_crate_mod() + new_parser_from_source_str(sess, name, source).parse_crate_mod() } -pub fn parse_crate_attrs_from_source_str<'a>(name: String, - source: String, - cfg: ast::CrateConfig, - sess: &'a ParseSess) +pub fn parse_crate_attrs_from_source_str<'a>(name: String, source: String, sess: &'a ParseSess) -> PResult<'a, Vec> { - let mut p = new_parser_from_source_str(sess, - cfg, - name, - source); - p.parse_inner_attributes() + new_parser_from_source_str(sess, name, source).parse_inner_attributes() } -pub fn parse_expr_from_source_str<'a>(name: String, - source: String, - cfg: ast::CrateConfig, - sess: &'a ParseSess) +pub fn parse_expr_from_source_str<'a>(name: String, source: String, sess: &'a ParseSess) -> PResult<'a, P> { - let mut p = new_parser_from_source_str(sess, cfg, name, source); - p.parse_expr() + new_parser_from_source_str(sess, name, source).parse_expr() } /// Parses an item. /// /// Returns `Ok(Some(item))` when successful, `Ok(None)` when no item was found, and`Err` /// when a syntax error occurred. -pub fn parse_item_from_source_str<'a>(name: String, - source: String, - cfg: ast::CrateConfig, - sess: &'a ParseSess) +pub fn parse_item_from_source_str<'a>(name: String, source: String, sess: &'a ParseSess) -> PResult<'a, Option>> { - let mut p = new_parser_from_source_str(sess, cfg, name, source); - p.parse_item() + new_parser_from_source_str(sess, name, source).parse_item() } -pub fn parse_meta_from_source_str<'a>(name: String, - source: String, - cfg: ast::CrateConfig, - sess: &'a ParseSess) +pub fn parse_meta_from_source_str<'a>(name: String, source: String, sess: &'a ParseSess) -> PResult<'a, P> { - let mut p = new_parser_from_source_str(sess, cfg, name, source); - p.parse_meta_item() + new_parser_from_source_str(sess, name, source).parse_meta_item() } -pub fn parse_stmt_from_source_str<'a>(name: String, - source: String, - cfg: ast::CrateConfig, - sess: &'a ParseSess) +pub fn parse_stmt_from_source_str<'a>(name: String, source: String, sess: &'a ParseSess) -> PResult<'a, Option> { - let mut p = new_parser_from_source_str( - sess, - cfg, - name, - source - ); - p.parse_stmt() + new_parser_from_source_str(sess, name, source).parse_stmt() } // Warning: This parses with quote_depth > 0, which is not the default. -pub fn parse_tts_from_source_str<'a>(name: String, - source: String, - cfg: ast::CrateConfig, - sess: &'a ParseSess) +pub fn parse_tts_from_source_str<'a>(name: String, source: String, sess: &'a ParseSess) -> PResult<'a, Vec> { - let mut p = new_parser_from_source_str( - sess, - cfg, - name, - source - ); + let mut p = new_parser_from_source_str(sess, name, source); p.quote_depth += 1; // right now this is re-creating the token trees from ... token trees. p.parse_all_token_trees() } // Create a new parser from a source string -pub fn new_parser_from_source_str<'a>(sess: &'a ParseSess, - cfg: ast::CrateConfig, - name: String, - source: String) +pub fn new_parser_from_source_str<'a>(sess: &'a ParseSess, name: String, source: String) -> Parser<'a> { - filemap_to_parser(sess, sess.codemap().new_filemap(name, None, source), cfg) + filemap_to_parser(sess, sess.codemap().new_filemap(name, None, source)) } /// Create a new parser, handling errors as appropriate /// if the file doesn't exist -pub fn new_parser_from_file<'a>(sess: &'a ParseSess, - cfg: ast::CrateConfig, - path: &Path) -> Parser<'a> { - filemap_to_parser(sess, file_to_filemap(sess, path, None), cfg) +pub fn new_parser_from_file<'a>(sess: &'a ParseSess, path: &Path) -> Parser<'a> { + filemap_to_parser(sess, file_to_filemap(sess, path, None)) } /// Given a session, a crate config, a path, and a span, add /// the file at the given path to the codemap, and return a parser. /// On an error, use the given span as the source of the problem. pub fn new_sub_parser_from_file<'a>(sess: &'a ParseSess, - cfg: ast::CrateConfig, path: &Path, owns_directory: bool, module_name: Option, sp: Span) -> Parser<'a> { - let mut p = filemap_to_parser(sess, file_to_filemap(sess, path, Some(sp)), cfg); + let mut p = filemap_to_parser(sess, file_to_filemap(sess, path, Some(sp))); p.owns_directory = owns_directory; p.root_module_name = module_name; p } /// Given a filemap and config, return a parser -pub fn filemap_to_parser<'a>(sess: &'a ParseSess, - filemap: Rc, - cfg: ast::CrateConfig) -> Parser<'a> { +pub fn filemap_to_parser<'a>(sess: &'a ParseSess, filemap: Rc, ) -> Parser<'a> { let end_pos = filemap.end_pos; - let mut parser = tts_to_parser(sess, filemap_to_tts(sess, filemap), cfg); + let mut parser = tts_to_parser(sess, filemap_to_tts(sess, filemap)); if parser.token == token::Eof && parser.span == syntax_pos::DUMMY_SP { parser.span = syntax_pos::mk_sp(end_pos, end_pos); @@ -228,18 +174,13 @@ pub fn filemap_to_parser<'a>(sess: &'a ParseSess, // must preserve old name for now, because quote! from the *existing* // compiler expands into it -pub fn new_parser_from_tts<'a>(sess: &'a ParseSess, - cfg: ast::CrateConfig, - tts: Vec) +pub fn new_parser_from_tts<'a>(sess: &'a ParseSess, tts: Vec) -> Parser<'a> { - tts_to_parser(sess, tts, cfg) + tts_to_parser(sess, tts) } -pub fn new_parser_from_ts<'a>(sess: &'a ParseSess, - cfg: ast::CrateConfig, - ts: tokenstream::TokenStream) - -> Parser<'a> { - tts_to_parser(sess, ts.to_tts(), cfg) +pub fn new_parser_from_ts<'a>(sess: &'a ParseSess, ts: tokenstream::TokenStream) -> Parser<'a> { + tts_to_parser(sess, ts.to_tts()) } @@ -266,18 +207,15 @@ pub fn filemap_to_tts(sess: &ParseSess, filemap: Rc) -> Vec { // it appears to me that the cfg doesn't matter here... indeed, // parsing tt's probably shouldn't require a parser at all. - let cfg = Vec::new(); let srdr = lexer::StringReader::new(&sess.span_diagnostic, filemap); - let mut p1 = Parser::new(sess, cfg, Box::new(srdr)); + let mut p1 = Parser::new(sess, Box::new(srdr)); panictry!(p1.parse_all_token_trees()) } -/// Given tts and cfg, produce a parser -pub fn tts_to_parser<'a>(sess: &'a ParseSess, - tts: Vec, - 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::new(trdr)); +/// Given tts and the ParseSess, produce a parser +pub fn tts_to_parser<'a>(sess: &'a ParseSess, tts: Vec) -> Parser<'a> { + let trdr = lexer::new_tt_reader(&sess.span_diagnostic, None, tts); + let mut p = Parser::new(sess, Box::new(trdr)); p.check_unknown_macro_variable(); p } @@ -686,12 +624,12 @@ mod tests { node: ast::ExprKind::Path(None, ast::Path { span: sp(0, 1), global: false, - segments: vec!( + segments: vec![ ast::PathSegment { identifier: str_to_ident("a"), parameters: ast::PathParameters::none(), } - ), + ], }), span: sp(0, 1), attrs: ThinVec::new(), @@ -705,7 +643,7 @@ mod tests { node: ast::ExprKind::Path(None, ast::Path { span: sp(0, 6), global: true, - segments: vec!( + segments: vec![ ast::PathSegment { identifier: str_to_ident("a"), parameters: ast::PathParameters::none(), @@ -714,7 +652,7 @@ mod tests { identifier: str_to_ident("b"), parameters: ast::PathParameters::none(), } - ) + ] }), span: sp(0, 6), attrs: ThinVec::new(), @@ -825,12 +763,12 @@ mod tests { node:ast::ExprKind::Path(None, ast::Path{ span: sp(7, 8), global: false, - segments: vec!( + segments: vec![ ast::PathSegment { identifier: str_to_ident("d"), parameters: ast::PathParameters::none(), } - ), + ], }), span:sp(7,8), attrs: ThinVec::new(), @@ -848,12 +786,12 @@ mod tests { node: ast::ExprKind::Path(None, ast::Path { span:sp(0,1), global:false, - segments: vec!( + segments: vec![ ast::PathSegment { identifier: str_to_ident("b"), parameters: ast::PathParameters::none(), } - ), + ], }), span: sp(0,1), attrs: ThinVec::new()})), @@ -890,18 +828,18 @@ mod tests { attrs:Vec::new(), id: ast::DUMMY_NODE_ID, node: ast::ItemKind::Fn(P(ast::FnDecl { - inputs: vec!(ast::Arg{ + inputs: vec![ast::Arg{ ty: P(ast::Ty{id: ast::DUMMY_NODE_ID, node: ast::TyKind::Path(None, ast::Path{ span:sp(10,13), global:false, - segments: vec!( + segments: vec![ ast::PathSegment { identifier: str_to_ident("i32"), parameters: ast::PathParameters::none(), } - ), + ], }), span:sp(10,13) }), @@ -917,7 +855,7 @@ mod tests { span: sp(6,7) }), id: ast::DUMMY_NODE_ID - }), + }], output: ast::FunctionRetTy::Default(sp(15, 15)), variadic: false }), @@ -937,14 +875,14 @@ mod tests { span: syntax_pos::DUMMY_SP, }, P(ast::Block { - stmts: vec!(ast::Stmt { + stmts: vec![ast::Stmt { node: ast::StmtKind::Semi(P(ast::Expr{ id: ast::DUMMY_NODE_ID, node: ast::ExprKind::Path(None, ast::Path{ span:sp(17,18), global:false, - segments: vec!( + segments: vec![ ast::PathSegment { identifier: str_to_ident( @@ -952,12 +890,12 @@ mod tests { parameters: ast::PathParameters::none(), } - ), + ], }), span: sp(17,18), attrs: ThinVec::new()})), id: ast::DUMMY_NODE_ID, - span: sp(17,19)}), + span: sp(17,19)}], id: ast::DUMMY_NODE_ID, rules: ast::BlockCheckMode::Default, // no idea span: sp(15,21), @@ -1057,13 +995,13 @@ mod tests { let name = "".to_string(); let source = "/// doc comment\r\nfn foo() {}".to_string(); - let item = parse_item_from_source_str(name.clone(), source, Vec::new(), &sess) + let item = parse_item_from_source_str(name.clone(), source, &sess) .unwrap().unwrap(); let doc = first_attr_value_str_by_name(&item.attrs, "doc").unwrap(); assert_eq!(&doc[..], "/// doc comment"); let source = "/// doc comment\r\n/// line 2\r\nfn foo() {}".to_string(); - let item = parse_item_from_source_str(name.clone(), source, Vec::new(), &sess) + let item = parse_item_from_source_str(name.clone(), source, &sess) .unwrap().unwrap(); let docs = item.attrs.iter().filter(|a| &*a.name() == "doc") .map(|a| a.value_str().unwrap().to_string()).collect::>(); @@ -1071,7 +1009,7 @@ mod tests { assert_eq!(&docs[..], b); let source = "/** doc comment\r\n * with CRLF */\r\nfn foo() {}".to_string(); - let item = parse_item_from_source_str(name, source, Vec::new(), &sess).unwrap().unwrap(); + let item = parse_item_from_source_str(name, source, &sess).unwrap().unwrap(); let doc = first_attr_value_str_by_name(&item.attrs, "doc").unwrap(); assert_eq!(&doc[..], "/** doc comment\n * with CRLF */"); } @@ -1080,7 +1018,7 @@ mod tests { fn ttdelim_span() { let sess = ParseSess::new(); let expr = parse::parse_expr_from_source_str("foo".to_string(), - "foo!( fn main() { body } )".to_string(), vec![], &sess).unwrap(); + "foo!( fn main() { body } )".to_string(), &sess).unwrap(); let tts = match expr.node { ast::ExprKind::Mac(ref mac) => mac.node.tts.clone(), diff --git a/src/libsyntax/parse/parser.rs b/src/libsyntax/parse/parser.rs index d5ed1d157e..b670a73847 100644 --- a/src/libsyntax/parse/parser.rs +++ b/src/libsyntax/parse/parser.rs @@ -15,7 +15,7 @@ use ast::Unsafety; use ast::{Mod, Arg, Arm, Attribute, BindingMode, TraitItemKind}; use ast::Block; use ast::{BlockCheckMode, CaptureBy}; -use ast::{Constness, Crate, CrateConfig}; +use ast::{Constness, Crate}; use ast::Defaultness; use ast::EnumDef; use ast::{Expr, ExprKind, RangeLimits}; @@ -48,8 +48,7 @@ use parse::classify; use parse::common::SeqSep; use parse::lexer::{Reader, TokenAndSpan}; use parse::obsolete::ObsoleteSyntax; -use parse::token::{self, intern, MatchNt, SubstNt, SpecialVarNt, InternedString}; -use parse::token::{keywords, SpecialMacroVar}; +use parse::token::{self, intern, keywords, MatchNt, SubstNt, InternedString}; use parse::{new_sub_parser_from_file, ParseSess}; use util::parser::{AssocOp, Fixity}; use print::pprust; @@ -108,125 +107,41 @@ pub enum SemiColonMode { /// be. The important thing is to make sure that lookahead doesn't balk at /// `token::Interpolated` tokens. macro_rules! maybe_whole_expr { - ($p:expr) => ( - { - let found = match $p.token { - token::Interpolated(token::NtExpr(ref e)) => { - Some((*e).clone()) + ($p:expr) => { + if let token::Interpolated(nt) = $p.token.clone() { + match *nt { + token::NtExpr(ref e) => { + $p.bump(); + return Ok((*e).clone()); } - token::Interpolated(token::NtPath(_)) => { - // FIXME: The following avoids an issue with lexical borrowck scopes, - // but the clone is unfortunate. - let pt = match $p.token { - token::Interpolated(token::NtPath(ref pt)) => (**pt).clone(), - _ => unreachable!() - }; + token::NtPath(ref path) => { + $p.bump(); let span = $p.span; - Some($p.mk_expr(span.lo, span.hi, ExprKind::Path(None, pt), ThinVec::new())) + let kind = ExprKind::Path(None, (*path).clone()); + return Ok($p.mk_expr(span.lo, span.hi, kind, ThinVec::new())); } - token::Interpolated(token::NtBlock(_)) => { - // FIXME: The following avoids an issue with lexical borrowck scopes, - // but the clone is unfortunate. - let b = match $p.token { - token::Interpolated(token::NtBlock(ref b)) => (*b).clone(), - _ => unreachable!() - }; + token::NtBlock(ref block) => { + $p.bump(); let span = $p.span; - Some($p.mk_expr(span.lo, span.hi, ExprKind::Block(b), ThinVec::new())) + let kind = ExprKind::Block((*block).clone()); + return Ok($p.mk_expr(span.lo, span.hi, kind, ThinVec::new())); } - _ => None + _ => {}, }; - match found { - Some(e) => { - $p.bump(); - return Ok(e); - } - None => () - } } - ) + } } /// As maybe_whole_expr, but for things other than expressions macro_rules! maybe_whole { - ($p:expr, $constructor:ident) => ( - { - let found = match ($p).token { - token::Interpolated(token::$constructor(_)) => { - Some(($p).bump_and_get()) - } - _ => None - }; - if let Some(token::Interpolated(token::$constructor(x))) = found { - return Ok(x.clone()); - } - } - ); - (no_clone $p:expr, $constructor:ident) => ( - { - let found = match ($p).token { - token::Interpolated(token::$constructor(_)) => { - Some(($p).bump_and_get()) - } - _ => None - }; - if let Some(token::Interpolated(token::$constructor(x))) = found { - return Ok(x); + ($p:expr, $constructor:ident, |$x:ident| $e:expr) => { + if let token::Interpolated(nt) = $p.token.clone() { + if let token::$constructor($x) = (*nt).clone() { + $p.bump(); + return Ok($e); } } - ); - (no_clone_from_p $p:expr, $constructor:ident) => ( - { - let found = match ($p).token { - token::Interpolated(token::$constructor(_)) => { - Some(($p).bump_and_get()) - } - _ => None - }; - if let Some(token::Interpolated(token::$constructor(x))) = found { - return Ok(x.unwrap()); - } - } - ); - (deref $p:expr, $constructor:ident) => ( - { - let found = match ($p).token { - token::Interpolated(token::$constructor(_)) => { - Some(($p).bump_and_get()) - } - _ => None - }; - if let Some(token::Interpolated(token::$constructor(x))) = found { - return Ok((*x).clone()); - } - } - ); - (Some deref $p:expr, $constructor:ident) => ( - { - let found = match ($p).token { - token::Interpolated(token::$constructor(_)) => { - Some(($p).bump_and_get()) - } - _ => None - }; - if let Some(token::Interpolated(token::$constructor(x))) = found { - return Ok(Some((*x).clone())); - } - } - ); - (pair_empty $p:expr, $constructor:ident) => ( - { - let found = match ($p).token { - token::Interpolated(token::$constructor(_)) => { - Some(($p).bump_and_get()) - } - _ => None - }; - if let Some(token::Interpolated(token::$constructor(x))) = found { - return Ok((Vec::new(), x)); - } - } - ) + }; } fn maybe_append(mut lhs: Vec, rhs: Option>) @@ -238,7 +153,7 @@ fn maybe_append(mut lhs: Vec, rhs: Option>) } #[derive(PartialEq)] -enum LastTokenKind { +enum PrevTokenKind { DocComment, Comma, Interpolated, @@ -246,6 +161,22 @@ enum LastTokenKind { Other, } +// Simple circular buffer used for keeping few next tokens. +#[derive(Default)] +struct LookaheadBuffer { + buffer: [TokenAndSpan; LOOKAHEAD_BUFFER_CAPACITY], + start: usize, + end: usize, +} + +const LOOKAHEAD_BUFFER_CAPACITY: usize = 8; + +impl LookaheadBuffer { + fn len(&self) -> usize { + (LOOKAHEAD_BUFFER_CAPACITY + self.end - self.start) % LOOKAHEAD_BUFFER_CAPACITY + } +} + /* ident is handled by common.rs */ pub struct Parser<'a> { @@ -254,14 +185,11 @@ pub struct Parser<'a> { pub token: token::Token, /// the span of the current token: pub span: Span, - /// the span of the prior token: - pub last_span: Span, - pub cfg: CrateConfig, + /// the span of the previous token: + pub prev_span: Span, /// the previous token kind - last_token_kind: LastTokenKind, - pub buffer: [TokenAndSpan; 4], - pub buffer_start: isize, - pub buffer_end: isize, + prev_token_kind: PrevTokenKind, + lookahead_buffer: LookaheadBuffer, pub tokens_consumed: usize, pub restrictions: Restrictions, pub quote_depth: usize, // not (yet) related to the quasiquoter @@ -282,6 +210,9 @@ pub struct Parser<'a> { /// into modules, and sub-parsers have new values for this name. pub root_module_name: Option, pub expected_tokens: Vec, + pub tts: Vec<(TokenTree, usize)>, + pub desugar_doc_comments: bool, + pub allow_interpolated_tts: bool, } #[derive(PartialEq, Eq, Clone)] @@ -345,49 +276,82 @@ impl From> for LhsExpr { } impl<'a> Parser<'a> { - pub fn new(sess: &'a ParseSess, - cfg: ast::CrateConfig, - mut rdr: Box) - -> Parser<'a> - { - let tok0 = rdr.real_token(); - let span = tok0.sp; - let mut directory = match span { - syntax_pos::DUMMY_SP => PathBuf::new(), - _ => PathBuf::from(sess.codemap().span_to_filename(span)), - }; - directory.pop(); - let placeholder = TokenAndSpan { - tok: token::Underscore, - sp: span, - }; + pub fn new(sess: &'a ParseSess, rdr: Box) -> Self { + Parser::new_with_doc_flag(sess, rdr, false) + } - Parser { + pub fn new_with_doc_flag(sess: &'a ParseSess, rdr: Box, desugar_doc_comments: bool) + -> Self { + let mut parser = Parser { reader: rdr, sess: sess, - cfg: cfg, - token: tok0.tok, - span: span, - last_span: span, - last_token_kind: LastTokenKind::Other, - buffer: [ - placeholder.clone(), - placeholder.clone(), - placeholder.clone(), - placeholder.clone(), - ], - buffer_start: 0, - buffer_end: 0, + token: token::Underscore, + span: syntax_pos::DUMMY_SP, + prev_span: syntax_pos::DUMMY_SP, + prev_token_kind: PrevTokenKind::Other, + lookahead_buffer: Default::default(), tokens_consumed: 0, restrictions: Restrictions::empty(), quote_depth: 0, parsing_token_tree: false, obsolete_set: HashSet::new(), - directory: directory, + directory: PathBuf::new(), open_braces: Vec::new(), owns_directory: true, root_module_name: None, expected_tokens: Vec::new(), + tts: Vec::new(), + desugar_doc_comments: desugar_doc_comments, + allow_interpolated_tts: true, + }; + + let tok = parser.next_tok(); + parser.token = tok.tok; + parser.span = tok.sp; + if parser.span != syntax_pos::DUMMY_SP { + parser.directory = PathBuf::from(sess.codemap().span_to_filename(parser.span)); + parser.directory.pop(); + } + parser + } + + fn next_tok(&mut self) -> TokenAndSpan { + 'outer: loop { + let mut tok = if let Some((tts, i)) = self.tts.pop() { + let tt = tts.get_tt(i); + if i + 1 < tts.len() { + self.tts.push((tts, i + 1)); + } + if let TokenTree::Token(sp, tok) = tt { + TokenAndSpan { tok: tok, sp: sp } + } else { + self.tts.push((tt, 0)); + continue + } + } else { + self.reader.real_token() + }; + + loop { + let nt = match tok.tok { + token::Interpolated(ref nt) => nt.clone(), + token::DocComment(name) if self.desugar_doc_comments => { + self.tts.push((TokenTree::Token(tok.sp, token::DocComment(name)), 0)); + continue 'outer + } + _ => return tok, + }; + match *nt { + token::NtTT(TokenTree::Token(sp, ref t)) => { + tok = TokenAndSpan { tok: t.clone(), sp: sp }; + } + token::NtTT(ref tt) => { + self.tts.push((tt.clone(), 0)); + continue 'outer + } + _ => return tok, + } + } } } @@ -414,8 +378,7 @@ impl<'a> Parser<'a> { pub fn unexpected_last(&self, t: &token::Token) -> PResult<'a, T> { let token_str = Parser::token_to_string(t); - let last_span = self.last_span; - Err(self.span_fatal(last_span, &format!("unexpected token: `{}`", token_str))) + Err(self.span_fatal(self.prev_span, &format!("unexpected token: `{}`", token_str))) } pub fn unexpected(&mut self) -> PResult<'a, T> { @@ -505,8 +468,8 @@ impl<'a> Parser<'a> { expr: PResult<'a, P>) -> PResult<'a, (Span, P)> { expr.map(|e| { - if self.last_token_kind == LastTokenKind::Interpolated { - (self.last_span, e) + if self.prev_token_kind == PrevTokenKind::Interpolated { + (self.prev_span, e) } else { (e.span, e) } @@ -521,12 +484,9 @@ impl<'a> Parser<'a> { self.bump(); Ok(i) } - token::Interpolated(token::NtIdent(..)) => { - self.bug("ident interpolation not converted to real token"); - } _ => { - Err(if self.last_token_kind == LastTokenKind::DocComment { - self.span_fatal_help(self.last_span, + Err(if self.prev_token_kind == PrevTokenKind::DocComment { + self.span_fatal_help(self.prev_span, "found a documentation comment that doesn't document anything", "doc comments must come before what they document, maybe a comment was \ intended with `//`?") @@ -853,7 +813,7 @@ impl<'a> Parser<'a> { Fe: FnMut(DiagnosticBuilder) { let mut first: bool = true; - let mut v = vec!(); + let mut v = vec![]; while !kets.contains(&&self.token) { match sep.sep { Some(ref t) => { @@ -923,35 +883,29 @@ impl<'a> Parser<'a> { /// Advance the parser by one token pub fn bump(&mut self) { - if self.last_token_kind == LastTokenKind::Eof { + if self.prev_token_kind == PrevTokenKind::Eof { // Bumping after EOF is a bad sign, usually an infinite loop. self.bug("attempted to bump the parser past EOF (may be stuck in a loop)"); } - self.last_span = self.span; + self.prev_span = self.span; // Record last token kind for possible error recovery. - self.last_token_kind = match self.token { - token::DocComment(..) => LastTokenKind::DocComment, - token::Comma => LastTokenKind::Comma, - token::Interpolated(..) => LastTokenKind::Interpolated, - token::Eof => LastTokenKind::Eof, - _ => LastTokenKind::Other, + self.prev_token_kind = match self.token { + token::DocComment(..) => PrevTokenKind::DocComment, + token::Comma => PrevTokenKind::Comma, + token::Interpolated(..) => PrevTokenKind::Interpolated, + token::Eof => PrevTokenKind::Eof, + _ => PrevTokenKind::Other, }; - let next = if self.buffer_start == self.buffer_end { - self.reader.real_token() + let next = if self.lookahead_buffer.start == self.lookahead_buffer.end { + self.next_tok() } else { // Avoid token copies with `replace`. - let buffer_start = self.buffer_start as usize; - let next_index = (buffer_start + 1) & 3; - self.buffer_start = next_index as isize; - - let placeholder = TokenAndSpan { - tok: token::Underscore, - sp: self.span, - }; - mem::replace(&mut self.buffer[buffer_start], placeholder) + let old_start = self.lookahead_buffer.start; + self.lookahead_buffer.start = (old_start + 1) % LOOKAHEAD_BUFFER_CAPACITY; + mem::replace(&mut self.lookahead_buffer.buffer[old_start], Default::default()) }; self.span = next.sp; self.token = next.tok; @@ -974,31 +928,32 @@ impl<'a> Parser<'a> { next: token::Token, lo: BytePos, hi: BytePos) { - self.last_span = mk_sp(self.span.lo, lo); + self.prev_span = mk_sp(self.span.lo, lo); // It would be incorrect to record the kind of the current token, but // fortunately for tokens currently using `bump_with`, the - // last_token_kind will be of no use anyway. - self.last_token_kind = LastTokenKind::Other; + // prev_token_kind will be of no use anyway. + self.prev_token_kind = PrevTokenKind::Other; self.span = mk_sp(lo, hi); self.token = next; self.expected_tokens.clear(); } - pub fn buffer_length(&mut self) -> isize { - if self.buffer_start <= self.buffer_end { - return self.buffer_end - self.buffer_start; - } - return (4 - self.buffer_start) + self.buffer_end; - } - pub fn look_ahead(&mut self, distance: usize, f: F) -> R where + pub fn look_ahead(&mut self, dist: usize, f: F) -> R where F: FnOnce(&token::Token) -> R, { - let dist = distance as isize; - while self.buffer_length() < dist { - self.buffer[self.buffer_end as usize] = self.reader.real_token(); - self.buffer_end = (self.buffer_end + 1) & 3; + if dist == 0 { + f(&self.token) + } else if dist < LOOKAHEAD_BUFFER_CAPACITY { + while self.lookahead_buffer.len() < dist { + self.lookahead_buffer.buffer[self.lookahead_buffer.end] = self.next_tok(); + self.lookahead_buffer.end = + (self.lookahead_buffer.end + 1) % LOOKAHEAD_BUFFER_CAPACITY; + } + let index = (self.lookahead_buffer.start + dist - 1) % LOOKAHEAD_BUFFER_CAPACITY; + f(&self.lookahead_buffer.buffer[index].tok) + } else { + self.bug("lookahead distance is too large"); } - f(&self.buffer[((self.buffer_start + dist - 1) & 3) as usize].tok) } pub fn fatal(&self, m: &str) -> DiagnosticBuilder<'a> { self.sess.span_diagnostic.struct_span_fatal(self.span, m) @@ -1114,14 +1069,12 @@ impl<'a> Parser<'a> { let bounds = self.parse_ty_param_bounds(BoundParsingMode::Modified)?; if !bounds.iter().any(|b| if let TraitTyParamBound(..) = *b { true } else { false }) { - let last_span = self.last_span; - self.span_err(last_span, "at least one trait must be specified"); + self.span_err(self.prev_span, "at least one trait must be specified"); } Ok(ast::TyKind::ImplTrait(bounds)) } - pub fn parse_ty_path(&mut self) -> PResult<'a, TyKind> { Ok(TyKind::Path(None, self.parse_path(PathStyle::Type)?)) } @@ -1174,12 +1127,12 @@ impl<'a> Parser<'a> { /// Parse the items in a trait declaration pub fn parse_trait_item(&mut self) -> PResult<'a, TraitItem> { - maybe_whole!(no_clone_from_p self, NtTraitItem); + maybe_whole!(self, NtTraitItem, |x| x); let mut attrs = self.parse_outer_attributes()?; let lo = self.span.lo; let (name, node) = if self.eat_keyword(keywords::Type) { - let TyParam {ident, bounds, default, ..} = self.parse_ty_param()?; + let TyParam {ident, bounds, default, ..} = self.parse_ty_param(vec![])?; self.expect(&token::Semi)?; (ident, TraitItemKind::Type(bounds, default)) } else if self.is_const_item() { @@ -1213,7 +1166,7 @@ impl<'a> Parser<'a> { self.expect(&token::Semi)? } - let mac = spanned(lo, self.last_span.hi, Mac_ { path: pth, tts: tts }); + let mac = spanned(lo, self.prev_span.hi, Mac_ { path: pth, tts: tts }); (keywords::Invalid.ident(), ast::TraitItemKind::Macro(mac)) } else { let (constness, unsafety, abi) = match self.parse_fn_front_matter() { @@ -1283,7 +1236,7 @@ impl<'a> Parser<'a> { ident: name, attrs: attrs, node: node, - span: mk_sp(lo, self.last_span.hi), + span: mk_sp(lo, self.prev_span.hi), }) } @@ -1330,20 +1283,20 @@ impl<'a> Parser<'a> { // In type grammar, `+` is treated like a binary operator, // and hence both L and R side are required. if bounds.is_empty() { - let last_span = self.last_span; - self.span_err(last_span, + let prev_span = self.prev_span; + self.span_err(prev_span, "at least one type parameter bound \ must be specified"); } - let sp = mk_sp(lo, self.last_span.hi); + let sp = mk_sp(lo, self.prev_span.hi); let sum = ast::TyKind::ObjectSum(lhs, bounds); Ok(P(Ty {id: ast::DUMMY_NODE_ID, node: sum, span: sp})) } /// Parse a type. pub fn parse_ty(&mut self) -> PResult<'a, P> { - maybe_whole!(no_clone self, NtTy); + maybe_whole!(self, NtTy, |x| x); let lo = self.span.lo; @@ -1386,8 +1339,8 @@ impl<'a> Parser<'a> { // Parse the `; e` in `[ i32; e ]` // where `e` is a const expression let t = match self.maybe_parse_fixed_length_of_vec()? { - None => TyKind::Vec(t), - Some(suffix) => TyKind::FixedLengthVec(t, suffix) + None => TyKind::Slice(t), + Some(suffix) => TyKind::Array(t, suffix) }; self.expect(&token::CloseDelim(token::Bracket))?; t @@ -1438,7 +1391,7 @@ impl<'a> Parser<'a> { return Err(self.fatal(&msg)); }; - let sp = mk_sp(lo, self.last_span.hi); + let sp = mk_sp(lo, self.prev_span.hi); Ok(P(Ty {id: ast::DUMMY_NODE_ID, node: t, span: sp})) } @@ -1456,7 +1409,7 @@ impl<'a> Parser<'a> { } else if self.eat_keyword(keywords::Const) { Mutability::Immutable } else { - let span = self.last_span; + let span = self.prev_span; self.span_err(span, "expected mut or const in raw pointer type (use \ `*mut T` or `*const T` as appropriate)"); @@ -1488,7 +1441,7 @@ 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) -> PResult<'a, Arg> { - maybe_whole!(no_clone self, NtArg); + maybe_whole!(self, NtArg, |x| x); let pat = if require_name || self.is_named_argument() { debug!("parse_arg_general parse_pat (require_name:{})", @@ -1499,7 +1452,7 @@ impl<'a> Parser<'a> { pat } else { debug!("parse_arg_general ident_to_pat"); - let sp = self.last_span; + let sp = self.prev_span; let spanned = Spanned { span: sp, node: keywords::Invalid.ident() }; P(Pat { id: ast::DUMMY_NODE_ID, @@ -1554,12 +1507,13 @@ impl<'a> Parser<'a> { /// Matches token_lit = LIT_INTEGER | ... pub fn parse_lit_token(&mut self) -> PResult<'a, LitKind> { let out = match self.token { - token::Interpolated(token::NtExpr(ref v)) => { - match v.node { + token::Interpolated(ref nt) => match **nt { + token::NtExpr(ref v) => match v.node { ExprKind::Lit(ref lit) => { lit.node.clone() } _ => { return self.unexpected_last(&self.token); } - } - } + }, + _ => { return self.unexpected_last(&self.token); } + }, token::Literal(lit, suf) => { let (suffix_illegal, out) = match lit { token::Byte(i) => (true, LitKind::Byte(parse::byte_lit(&i.as_str()).0)), @@ -1624,7 +1578,7 @@ impl<'a> Parser<'a> { let lit = self.parse_lit_token()?; lit }; - Ok(codemap::Spanned { node: lit, span: mk_sp(lo, self.last_span.hi) }) + Ok(codemap::Spanned { node: lit, span: mk_sp(lo, self.prev_span.hi) }) } /// matches '-' lit | lit @@ -1633,11 +1587,11 @@ impl<'a> Parser<'a> { let minus_present = self.eat(&token::BinOp(token::Minus)); let lo = self.span.lo; let literal = P(self.parse_lit()?); - let hi = self.last_span.hi; + let hi = self.prev_span.hi; let expr = self.mk_expr(lo, hi, ExprKind::Lit(literal), ThinVec::new()); if minus_present { - let minus_hi = self.last_span.hi; + let minus_hi = self.prev_span.hi; let unary = self.mk_unary(UnOp::Neg, expr); Ok(self.mk_expr(minus_lo, minus_hi, unary, ThinVec::new())) } else { @@ -1672,7 +1626,7 @@ impl<'a> Parser<'a> { /// `::F::a::` pub fn parse_qualified_path(&mut self, mode: PathStyle) -> PResult<'a, (QSelf, ast::Path)> { - let span = self.last_span; + let span = self.prev_span; let self_type = self.parse_ty_sum()?; let mut path = if self.eat_keyword(keywords::As) { self.parse_path(PathStyle::Type)? @@ -1705,7 +1659,7 @@ impl<'a> Parser<'a> { }; path.segments.extend(segments); - path.span.hi = self.last_span.hi; + path.span.hi = self.prev_span.hi; Ok((qself, path)) } @@ -1715,14 +1669,7 @@ impl<'a> Parser<'a> { /// bounds are permitted and whether `::` must precede type parameter /// groups. pub fn parse_path(&mut self, mode: PathStyle) -> PResult<'a, ast::Path> { - // Check for a whole path... - let found = match self.token { - token::Interpolated(token::NtPath(_)) => Some(self.bump_and_get()), - _ => None, - }; - if let Some(token::Interpolated(token::NtPath(path))) = found { - return Ok(*path); - } + maybe_whole!(self, NtPath, |x| x); let lo = self.span.lo; let is_global = self.eat(&token::ModSep); @@ -1743,7 +1690,7 @@ impl<'a> Parser<'a> { }; // Assemble the span. - let span = mk_sp(lo, self.last_span.hi); + let span = mk_sp(lo, self.prev_span.hi); // Assemble the result. Ok(ast::Path { @@ -1763,6 +1710,17 @@ impl<'a> Parser<'a> { // First, parse an identifier. let identifier = self.parse_path_segment_ident()?; + if self.check(&token::ModSep) && self.look_ahead(1, |t| *t == token::Lt) { + self.bump(); + let prev_span = self.prev_span; + + let mut err = self.diagnostic().struct_span_err(prev_span, + "unexpected token: `::`"); + err.help( + "use `<...>` instead of `::<...>` if you meant to specify type arguments"); + err.emit(); + } + // Parse types, optionally. let parameters = if self.eat_lt() { let (lifetimes, types, bindings) = self.parse_generic_values_after_lt()?; @@ -1773,7 +1731,7 @@ impl<'a> Parser<'a> { bindings: P::from_vec(bindings), }) } else if self.eat(&token::OpenDelim(token::Paren)) { - let lo = self.last_span.lo; + let lo = self.prev_span.lo; let inputs = self.parse_seq_to_end( &token::CloseDelim(token::Paren), @@ -1786,7 +1744,7 @@ impl<'a> Parser<'a> { None }; - let hi = self.last_span.hi; + let hi = self.prev_span.hi; ast::PathParameters::Parenthesized(ast::ParenthesizedParameterData { span: mk_sp(lo, hi), @@ -1910,10 +1868,22 @@ impl<'a> Parser<'a> { /// Parses `lifetime_defs = [ lifetime_defs { ',' lifetime_defs } ]` where `lifetime_def = /// lifetime [':' lifetimes]` - pub fn parse_lifetime_defs(&mut self) -> PResult<'a, Vec> { - + /// + /// If `followed_by_ty_params` is None, then we are in a context + /// where only lifetime parameters are allowed, and thus we should + /// error if we encounter attributes after the bound lifetimes. + /// + /// If `followed_by_ty_params` is Some(r), then there may be type + /// parameter bindings after the lifetimes, so we should pass + /// along the parsed attributes to be attached to the first such + /// type parmeter. + pub fn parse_lifetime_defs(&mut self, + followed_by_ty_params: Option<&mut Vec>) + -> PResult<'a, Vec> + { let mut res = Vec::new(); loop { + let attrs = self.parse_outer_attributes()?; match self.token { token::Lifetime(_) => { let lifetime = self.parse_lifetime()?; @@ -1923,11 +1893,20 @@ impl<'a> Parser<'a> { } else { Vec::new() }; - res.push(ast::LifetimeDef { lifetime: lifetime, + res.push(ast::LifetimeDef { attrs: attrs.into(), + lifetime: lifetime, bounds: bounds }); } _ => { + if let Some(recv) = followed_by_ty_params { + assert!(recv.is_empty()); + *recv = attrs; + } else { + let msg = "trailing attribute after lifetime parameters"; + return Err(self.fatal(msg)); + } + debug!("parse_lifetime_defs ret {:?}", res); return Ok(res); } } @@ -1992,17 +1971,30 @@ impl<'a> Parser<'a> { } } - /// Parse ident COLON expr + /// Parse ident (COLON expr)? pub fn parse_field(&mut self) -> PResult<'a, Field> { let lo = self.span.lo; - let i = self.parse_field_name()?; - let hi = self.last_span.hi; - self.expect(&token::Colon)?; - let e = self.parse_expr()?; + let hi; + + // Check if a colon exists one ahead. This means we're parsing a fieldname. + let (fieldname, expr, is_shorthand) = if self.look_ahead(1, |t| t == &token::Colon) { + let fieldname = self.parse_field_name()?; + self.bump(); + hi = self.prev_span.hi; + (fieldname, self.parse_expr()?, false) + } else { + let fieldname = self.parse_ident()?; + hi = self.prev_span.hi; + + // Mimic `x: x` for the `x` field shorthand. + let path = ast::Path::from_ident(mk_sp(lo, hi), fieldname); + (fieldname, self.mk_expr(lo, hi, ExprKind::Path(None, path), ThinVec::new()), true) + }; Ok(ast::Field { - ident: spanned(lo, hi, i), - span: mk_sp(lo, e.span.hi), - expr: e, + ident: spanned(lo, hi, fieldname), + span: mk_sp(lo, expr.span.hi), + expr: expr, + is_shorthand: is_shorthand, }) } @@ -2151,7 +2143,7 @@ impl<'a> Parser<'a> { } self.bump(); - hi = self.last_span.hi; + hi = self.prev_span.hi; return if es.len() == 1 && !trailing_comma { Ok(self.mk_expr(lo, hi, ExprKind::Paren(es.into_iter().nth(0).unwrap()), attrs)) } else { @@ -2191,16 +2183,16 @@ impl<'a> Parser<'a> { SeqSep::trailing_allowed(token::Comma), |p| Ok(p.parse_expr()?) )?; - let mut exprs = vec!(first_expr); + let mut exprs = vec![first_expr]; exprs.extend(remaining_exprs); ex = ExprKind::Vec(exprs); } else { // Vector with one element. self.expect(&token::CloseDelim(token::Bracket))?; - ex = ExprKind::Vec(vec!(first_expr)); + ex = ExprKind::Vec(vec![first_expr]); } } - hi = self.last_span.hi; + hi = self.prev_span.hi; } _ => { if self.eat_lt() { @@ -2210,18 +2202,18 @@ impl<'a> Parser<'a> { return Ok(self.mk_expr(lo, hi, ExprKind::Path(Some(qself), path), attrs)); } if self.eat_keyword(keywords::Move) { - let lo = self.last_span.lo; + let lo = self.prev_span.lo; return self.parse_lambda_expr(lo, CaptureBy::Value, attrs); } if self.eat_keyword(keywords::If) { return self.parse_if_expr(attrs); } if self.eat_keyword(keywords::For) { - let lo = self.last_span.lo; + let lo = self.prev_span.lo; return self.parse_for_expr(None, lo, attrs); } if self.eat_keyword(keywords::While) { - let lo = self.last_span.lo; + let lo = self.prev_span.lo; return self.parse_while_expr(None, lo, attrs); } if self.token.is_lifetime() { @@ -2242,7 +2234,7 @@ impl<'a> Parser<'a> { return Err(self.fatal("expected `while`, `for`, or `loop` after a label")) } if self.eat_keyword(keywords::Loop) { - let lo = self.last_span.lo; + let lo = self.prev_span.lo; return self.parse_loop_expr(None, lo, attrs); } if self.eat_keyword(keywords::Continue) { @@ -2256,7 +2248,7 @@ impl<'a> Parser<'a> { } else { ExprKind::Continue(None) }; - let hi = self.last_span.hi; + let hi = self.prev_span.hi; return Ok(self.mk_expr(lo, hi, ex, attrs)); } if self.eat_keyword(keywords::Match) { @@ -2286,7 +2278,7 @@ impl<'a> Parser<'a> { } else { ex = ExprKind::Break(None); } - hi = self.last_span.hi; + hi = self.prev_span.hi; } else if self.token.is_keyword(keywords::Let) { // Catch this syntax error here, instead of in `check_strict_keywords`, so // that we can explicitly mention that let is not to be used as an expression @@ -2303,7 +2295,7 @@ impl<'a> Parser<'a> { let tts = self.parse_seq_to_end(&token::CloseDelim(delim), SeqSep::none(), |p| p.parse_token_tree())?; - let hi = self.last_span.hi; + let hi = self.prev_span.hi; return Ok(self.mk_mac_expr(lo, hi, Mac_ { path: pth, tts: tts }, attrs)); } if self.check(&token::OpenDelim(token::Brace)) { @@ -2468,8 +2460,8 @@ impl<'a> Parser<'a> { }; if !bindings.is_empty() { - let last_span = self.last_span; - self.span_err(last_span, "type bindings are only permitted on trait paths"); + let prev_span = self.prev_span; + self.span_err(prev_span, "type bindings are only permitted on trait paths"); } Ok(match self.token { @@ -2481,7 +2473,7 @@ impl<'a> Parser<'a> { SeqSep::trailing_allowed(token::Comma), |p| Ok(p.parse_expr()?) )?; - let hi = self.last_span.hi; + let hi = self.prev_span.hi; es.insert(0, self_value); let id = spanned(ident_span.lo, ident_span.hi, ident); @@ -2491,8 +2483,8 @@ impl<'a> Parser<'a> { // Field access. _ => { if !tys.is_empty() { - let last_span = self.last_span; - self.span_err(last_span, + let prev_span = self.prev_span; + self.span_err(prev_span, "field expressions may not \ have type parameters"); } @@ -2510,7 +2502,7 @@ impl<'a> Parser<'a> { loop { // expr? while self.eat(&token::Question) { - let hi = self.last_span.hi; + let hi = self.prev_span.hi; e = self.mk_expr(lo, hi, ExprKind::Try(e), ThinVec::new()); } @@ -2518,7 +2510,7 @@ impl<'a> Parser<'a> { if self.eat(&token::Dot) { match self.token { token::Ident(i) => { - let dot_pos = self.last_span.hi; + let dot_pos = self.prev_span.hi; hi = self.span.hi; self.bump(); @@ -2530,7 +2522,7 @@ impl<'a> Parser<'a> { // A tuple index may not have a suffix self.expect_no_suffix(sp, "tuple index", suf); - let dot = self.last_span.hi; + let dot = self.prev_span.hi; hi = self.span.hi; self.bump(); @@ -2542,16 +2534,16 @@ impl<'a> Parser<'a> { e = self.mk_expr(lo, hi, field, ThinVec::new()); } None => { - let last_span = self.last_span; - self.span_err(last_span, "invalid tuple or tuple struct index"); + let prev_span = self.prev_span; + self.span_err(prev_span, "invalid tuple or tuple struct index"); } } } token::Literal(token::Float(n), _suf) => { self.bump(); - let last_span = self.last_span; + let prev_span = self.prev_span; let fstr = n.as_str(); - let mut err = self.diagnostic().struct_span_err(last_span, + let mut err = self.diagnostic().struct_span_err(prev_span, &format!("unexpected token: `{}`", n.as_str())); if fstr.chars().all(|x| "0123456789.".contains(x)) { let float = match fstr.parse::().ok() { @@ -2570,7 +2562,7 @@ impl<'a> Parser<'a> { let actual = self.this_token_to_string(); self.span_err(self.span, &format!("unexpected token: `{}`", actual)); - let dot_pos = self.last_span.hi; + let dot_pos = self.prev_span.hi; e = self.parse_dot_suffix(keywords::Invalid.ident(), mk_sp(dot_pos, dot_pos), e, lo)?; @@ -2588,7 +2580,7 @@ impl<'a> Parser<'a> { SeqSep::trailing_allowed(token::Comma), |p| Ok(p.parse_expr()?) )?; - hi = self.last_span.hi; + hi = self.prev_span.hi; let nd = self.mk_call(e, es); e = self.mk_expr(lo, hi, nd, ThinVec::new()); @@ -2634,8 +2626,12 @@ impl<'a> Parser<'a> { num_captures: name_num }))); } else if self.token.is_keyword(keywords::Crate) { + let ident = match self.token { + token::Ident(id) => ast::Ident { name: token::intern("$crate"), ..id }, + _ => unreachable!(), + }; self.bump(); - return Ok(TokenTree::Token(sp, SpecialVarNt(SpecialMacroVar::CrateMacroVar))); + return Ok(TokenTree::Token(sp, token::Ident(ident))); } else { sp = mk_sp(sp.lo, self.span.hi); self.parse_ident().unwrap_or_else(|mut e| { @@ -2709,8 +2705,6 @@ impl<'a> Parser<'a> { // and token::SubstNt's; it's too early to know yet // whether something will be a nonterminal or a seq // yet. - maybe_whole!(deref self, NtTT); - match self.token { token::Eof => { let mut err: DiagnosticBuilder<'a> = @@ -2723,6 +2717,17 @@ impl<'a> Parser<'a> { Err(err) }, token::OpenDelim(delim) => { + if self.tts.last().map(|&(_, i)| i == 1).unwrap_or(false) { + let tt = self.tts.pop().unwrap().0; + self.bump(); + return Ok(if self.allow_interpolated_tts { + // avoid needlessly reparsing token trees in recursive macro expansions + TokenTree::Token(tt.span(), token::Interpolated(Rc::new(token::NtTT(tt)))) + } else { + tt + }); + } + let parsing_token_tree = ::std::mem::replace(&mut self.parsing_token_tree, true); // The span for beginning of the delimited section let pre_span = self.span; @@ -2796,29 +2801,20 @@ impl<'a> Parser<'a> { close_span: close_span, }))) }, + token::CloseDelim(_) => { + // An unexpected closing delimiter (i.e., there is no + // matching opening delimiter). + let token_str = self.this_token_to_string(); + let err = self.diagnostic().struct_span_err(self.span, + &format!("unexpected close delimiter: `{}`", token_str)); + Err(err) + }, + /* we ought to allow different depths of unquotation */ + token::Dollar | token::SubstNt(..) if self.quote_depth > 0 => { + self.parse_unquoted() + } _ => { - // invariants: the current token is not a left-delimiter, - // not an EOF, and not the desired right-delimiter (if - // it were, parse_seq_to_before_end would have prevented - // reaching this point). - maybe_whole!(deref self, NtTT); - match self.token { - token::CloseDelim(_) => { - // An unexpected closing delimiter (i.e., there is no - // matching opening delimiter). - let token_str = self.this_token_to_string(); - let err = self.diagnostic().struct_span_err(self.span, - &format!("unexpected close delimiter: `{}`", token_str)); - Err(err) - }, - /* we ought to allow different depths of unquotation */ - token::Dollar | token::SubstNt(..) if self.quote_depth > 0 => { - self.parse_unquoted() - } - _ => { - Ok(TokenTree::Token(self.span, self.bump_and_get())) - } - } + Ok(TokenTree::Token(self.span, self.bump_and_get())) } } } @@ -2931,8 +2927,8 @@ impl<'a> Parser<'a> { self.expected_tokens.push(TokenType::Operator); while let Some(op) = AssocOp::from_token(&self.token) { - let lhs_span = if self.last_token_kind == LastTokenKind::Interpolated { - self.last_span + let lhs_span = if self.prev_token_kind == PrevTokenKind::Interpolated { + self.prev_span } else { lhs.span }; @@ -3125,7 +3121,7 @@ impl<'a> Parser<'a> { if self.check_keyword(keywords::Let) { return self.parse_if_let_expr(attrs); } - let lo = self.last_span.lo; + let lo = self.prev_span.lo; let cond = self.parse_expr_res(Restrictions::RESTRICTION_NO_STRUCT_LITERAL, None)?; let thn = self.parse_block()?; let mut els: Option> = None; @@ -3141,7 +3137,7 @@ impl<'a> Parser<'a> { /// Parse an 'if let' expression ('if' token already eaten) pub fn parse_if_let_expr(&mut self, attrs: ThinVec) -> PResult<'a, P> { - let lo = self.last_span.lo; + let lo = self.prev_span.lo; self.expect_keyword(keywords::Let)?; let pat = self.parse_pat()?; self.expect(&token::Eq)?; @@ -3164,7 +3160,7 @@ impl<'a> Parser<'a> { -> PResult<'a, P> { let decl = self.parse_fn_block_decl()?; - let decl_hi = self.last_span.hi; + let decl_hi = self.prev_span.hi; let body = match decl.output { FunctionRetTy::Default(_) => { // If no explicit return type is given, parse any @@ -3217,7 +3213,7 @@ impl<'a> Parser<'a> { let (iattrs, loop_block) = self.parse_inner_attrs_and_block()?; attrs.extend(iattrs); - let hi = self.last_span.hi; + let hi = self.prev_span.hi; Ok(self.mk_expr(span_lo, hi, ExprKind::ForLoop(pat, expr, loop_block, opt_ident), @@ -3265,8 +3261,8 @@ impl<'a> Parser<'a> { // `match` token already eaten fn parse_match_expr(&mut self, mut attrs: ThinVec) -> PResult<'a, P> { - let match_span = self.last_span; - let lo = self.last_span.lo; + let match_span = self.prev_span; + let lo = self.prev_span.lo; let discriminant = self.parse_expr_res(Restrictions::RESTRICTION_NO_STRUCT_LITERAL, None)?; if let Err(mut e) = self.expect(&token::OpenDelim(token::Brace)) { @@ -3299,7 +3295,7 @@ impl<'a> Parser<'a> { } pub fn parse_arm(&mut self) -> PResult<'a, Arm> { - maybe_whole!(no_clone self, NtArm); + maybe_whole!(self, NtArm, |x| x); let attrs = self.parse_outer_attributes()?; let pats = self.parse_pats()?; @@ -3388,7 +3384,7 @@ impl<'a> Parser<'a> { } } else if ddpos.is_some() && self.eat(&token::DotDot) { // Emit a friendly error, ignore `..` and continue parsing - self.span_err(self.last_span, "`..` can only be used once per \ + self.span_err(self.prev_span, "`..` can only be used once per \ tuple or tuple struct pattern"); } else { fields.push(self.parse_pat()?); @@ -3499,7 +3495,7 @@ impl<'a> Parser<'a> { let is_ref = self.eat_keyword(keywords::Ref); let is_mut = self.eat_keyword(keywords::Mut); let fieldname = self.parse_ident()?; - hi = self.last_span.hi; + hi = self.prev_span.hi; let bind_type = match (is_ref, is_mut) { (true, true) => BindingMode::ByRef(Mutability::Mutable), @@ -3507,7 +3503,7 @@ impl<'a> Parser<'a> { (false, true) => BindingMode::ByValue(Mutability::Mutable), (false, false) => BindingMode::ByValue(Mutability::Immutable), }; - let fieldpath = codemap::Spanned{span:self.last_span, node:fieldname}; + let fieldpath = codemap::Spanned{span:self.prev_span, node:fieldname}; let fieldpat = P(ast::Pat{ id: ast::DUMMY_NODE_ID, node: PatKind::Ident(bind_type, fieldpath, None), @@ -3546,7 +3542,7 @@ impl<'a> Parser<'a> { // Parse an unqualified path (None, self.parse_path(PathStyle::Expr)?) }; - let hi = self.last_span.hi; + let hi = self.prev_span.hi; Ok(self.mk_expr(lo, hi, ExprKind::Path(qself, path), ThinVec::new())) } else { self.parse_pat_literal_maybe_minus() @@ -3555,7 +3551,7 @@ impl<'a> Parser<'a> { /// Parse a pattern. pub fn parse_pat(&mut self) -> PResult<'a, P> { - maybe_whole!(self, NtPat); + maybe_whole!(self, NtPat, |x| x); let lo = self.span.lo; let pat; @@ -3587,7 +3583,7 @@ impl<'a> Parser<'a> { self.bump(); let (before, slice, after) = self.parse_pat_vec_elements()?; self.expect(&token::CloseDelim(token::Bracket))?; - pat = PatKind::Vec(before, slice, after); + pat = PatKind::Slice(before, slice, after); } // At this point, token != _, &, &&, (, [ _ => if self.eat_keyword(keywords::Mut) { @@ -3601,7 +3597,7 @@ impl<'a> Parser<'a> { // Parse box pat let subpat = self.parse_pat()?; pat = PatKind::Box(subpat); - } else if self.token.is_ident() && self.token.is_path_start() && + } else if self.token.is_ident() && !self.token.is_any_keyword() && self.look_ahead(1, |t| match *t { token::OpenDelim(token::Paren) | token::OpenDelim(token::Brace) | token::DotDotDot | token::ModSep | token::Not => false, @@ -3630,12 +3626,12 @@ impl<'a> Parser<'a> { let tts = self.parse_seq_to_end(&token::CloseDelim(delim), SeqSep::none(), |p| p.parse_token_tree())?; - let mac = spanned(lo, self.last_span.hi, Mac_ { path: path, tts: tts }); + let mac = spanned(lo, self.prev_span.hi, Mac_ { path: path, tts: tts }); pat = PatKind::Mac(mac); } token::DotDotDot => { // Parse range - let hi = self.last_span.hi; + let hi = self.prev_span.hi; let begin = self.mk_expr(lo, hi, ExprKind::Path(qself, path), ThinVec::new()); self.bump(); @@ -3688,7 +3684,7 @@ impl<'a> Parser<'a> { } } - let hi = self.last_span.hi; + let hi = self.prev_span.hi; Ok(P(ast::Pat { id: ast::DUMMY_NODE_ID, node: pat, @@ -3703,8 +3699,8 @@ impl<'a> Parser<'a> { binding_mode: ast::BindingMode) -> PResult<'a, PatKind> { let ident = self.parse_ident()?; - let last_span = self.last_span; - let name = codemap::Spanned{span: last_span, node: ident}; + let prev_span = self.prev_span; + let name = codemap::Spanned{span: prev_span, node: ident}; let sub = if self.eat(&token::At) { Some(self.parse_pat()?) } else { @@ -3718,9 +3714,8 @@ impl<'a> Parser<'a> { // binding mode then we do not end up here, because the lookahead // will direct us over to parse_enum_variant() if self.token == token::OpenDelim(token::Paren) { - let last_span = self.last_span; return Err(self.span_fatal( - last_span, + self.prev_span, "expected identifier, found enum pattern")) } @@ -3742,7 +3737,7 @@ impl<'a> Parser<'a> { pat: pat, init: init, id: ast::DUMMY_NODE_ID, - span: mk_sp(lo, self.last_span.hi), + span: mk_sp(lo, self.prev_span.hi), attrs: attrs, })) } @@ -3757,7 +3752,7 @@ impl<'a> Parser<'a> { self.expect(&token::Colon)?; let ty = self.parse_ty_sum()?; Ok(StructField { - span: mk_sp(lo, self.last_span.hi), + span: mk_sp(lo, self.prev_span.hi), ident: Some(name), vis: vis, id: ast::DUMMY_NODE_ID, @@ -3775,7 +3770,7 @@ impl<'a> Parser<'a> { _ => "expected item after attributes", }; - self.span_err(self.last_span, message); + self.span_err(self.prev_span, message); } /// Parse a statement. This stops just before trailing semicolons on everything but items. @@ -3853,10 +3848,15 @@ impl<'a> Parser<'a> { }) } + fn is_union_item(&mut self) -> bool { + self.token.is_keyword(keywords::Union) && + self.look_ahead(1, |t| t.is_ident() && !t.is_any_keyword()) + } + fn parse_stmt_without_recovery(&mut self, macro_legacy_warnings: bool) -> PResult<'a, Option> { - maybe_whole!(Some deref self, NtStmt); + maybe_whole!(self, NtStmt, |x| Some(x)); let attrs = self.parse_outer_attributes()?; let lo = self.span.lo; @@ -3865,19 +3865,19 @@ impl<'a> Parser<'a> { Stmt { id: ast::DUMMY_NODE_ID, node: StmtKind::Local(self.parse_local(attrs.into())?), - span: mk_sp(lo, self.last_span.hi), + span: mk_sp(lo, self.prev_span.hi), } - } else if self.token.is_path_start() && self.token != token::Lt && { - !self.check_keyword(keywords::Union) || - self.look_ahead(1, |t| *t == token::Not || *t == token::ModSep) - } { + // Starts like a simple path, but not a union item. + } else if self.token.is_path_start() && + !self.token.is_qpath_start() && + !self.is_union_item() { let pth = self.parse_path(PathStyle::Expr)?; if !self.eat(&token::Not) { let expr = if self.check(&token::OpenDelim(token::Brace)) { self.parse_struct_expr(lo, pth, ThinVec::new())? } else { - let hi = self.last_span.hi; + let hi = self.prev_span.hi; self.mk_expr(lo, hi, ExprKind::Path(None, pth), ThinVec::new()) }; @@ -3889,7 +3889,7 @@ impl<'a> Parser<'a> { return Ok(Some(Stmt { id: ast::DUMMY_NODE_ID, node: StmtKind::Expr(expr), - span: mk_sp(lo, self.last_span.hi), + span: mk_sp(lo, self.prev_span.hi), })); } @@ -3925,7 +3925,7 @@ impl<'a> Parser<'a> { SeqSep::none(), |p| p.parse_token_tree() )?; - let hi = self.last_span.hi; + let hi = self.prev_span.hi; let style = if delim == token::Brace { MacStmtStyle::Braces @@ -3970,8 +3970,7 @@ impl<'a> Parser<'a> { // Require a semicolon or braces. if style != MacStmtStyle::Braces { if !self.eat(&token::Semi) { - let last_span = self.last_span; - self.span_err(last_span, + self.span_err(self.prev_span, "macros that expand to items must \ either be surrounded with braces or \ followed by a semicolon"); @@ -4002,8 +4001,8 @@ impl<'a> Parser<'a> { None => { let unused_attrs = |attrs: &[_], s: &mut Self| { if attrs.len() > 0 { - if s.last_token_kind == LastTokenKind::DocComment { - s.span_err_help(s.last_span, + if s.prev_token_kind == PrevTokenKind::DocComment { + s.span_err_help(s.prev_span, "found a documentation comment that doesn't document anything", "doc comments must come before what they document, maybe a \ comment was intended with `//`?"); @@ -4046,7 +4045,7 @@ impl<'a> Parser<'a> { /// Parse a block. No inner attrs are allowed. pub fn parse_block(&mut self) -> PResult<'a, P> { - maybe_whole!(no_clone self, NtBlock); + maybe_whole!(self, NtBlock, |x| x); let lo = self.span.lo; @@ -4066,7 +4065,7 @@ impl<'a> Parser<'a> { let mut stmt_span = stmt.span; // expand the span to include the semicolon, if it exists if self.eat(&token::Semi) { - stmt_span.hi = self.last_span.hi; + stmt_span.hi = self.prev_span.hi; } e.span_help(stmt_span, "try placing this code inside a block"); } @@ -4084,7 +4083,7 @@ impl<'a> Parser<'a> { /// Parse a block. Inner attrs are allowed. fn parse_inner_attrs_and_block(&mut self) -> PResult<'a, (Vec, P)> { - maybe_whole!(pair_empty self, NtBlock); + maybe_whole!(self, NtBlock, |x| (Vec::new(), x)); let lo = self.span.lo; self.expect(&token::OpenDelim(token::Brace))?; @@ -4112,7 +4111,7 @@ impl<'a> Parser<'a> { stmts: stmts, id: ast::DUMMY_NODE_ID, rules: s, - span: mk_sp(lo, self.last_span.hi), + span: mk_sp(lo, self.prev_span.hi), })) } @@ -4151,7 +4150,7 @@ impl<'a> Parser<'a> { stmt = stmt.add_trailing_semicolon(); } - stmt.span.hi = self.last_span.hi; + stmt.span.hi = self.prev_span.hi; Ok(Some(stmt)) } @@ -4184,7 +4183,7 @@ impl<'a> Parser<'a> { mode: BoundParsingMode) -> PResult<'a, TyParamBounds> { - let mut result = vec!(); + let mut result = vec![]; loop { let question_span = self.span; let ate_question = self.eat(&token::Question); @@ -4228,7 +4227,7 @@ impl<'a> Parser<'a> { } /// Matches typaram = IDENT (`?` unbound)? optbounds ( EQ ty )? - fn parse_ty_param(&mut self) -> PResult<'a, TyParam> { + fn parse_ty_param(&mut self, preceding_attrs: Vec) -> PResult<'a, TyParam> { let span = self.span; let ident = self.parse_ident()?; @@ -4242,6 +4241,7 @@ impl<'a> Parser<'a> { }; Ok(TyParam { + attrs: preceding_attrs.into(), ident: ident, id: ast::DUMMY_NODE_ID, bounds: bounds, @@ -4258,24 +4258,46 @@ impl<'a> Parser<'a> { /// | ( < lifetimes , typaramseq ( , )? > ) /// where typaramseq = ( typaram ) | ( typaram , typaramseq ) pub fn parse_generics(&mut self) -> PResult<'a, ast::Generics> { - maybe_whole!(self, NtGenerics); + maybe_whole!(self, NtGenerics, |x| x); let span_lo = self.span.lo; if self.eat(&token::Lt) { - let lifetime_defs = self.parse_lifetime_defs()?; + // Upon encountering attribute in generics list, we do not + // know if it is attached to lifetime or to type param. + // + // Solution: 1. eagerly parse attributes in tandem with + // lifetime defs, 2. store last set of parsed (and unused) + // attributes in `attrs`, and 3. pass in those attributes + // when parsing formal type param after lifetime defs. + let mut attrs = vec![]; + let lifetime_defs = self.parse_lifetime_defs(Some(&mut attrs))?; let mut seen_default = false; + let mut post_lifetime_attrs = Some(attrs); let ty_params = self.parse_seq_to_gt(Some(token::Comma), |p| { p.forbid_lifetime()?; - let ty_param = p.parse_ty_param()?; + // Move out of `post_lifetime_attrs` if present. O/w + // not first type param: parse attributes anew. + let attrs = match post_lifetime_attrs.as_mut() { + None => p.parse_outer_attributes()?, + Some(attrs) => mem::replace(attrs, vec![]), + }; + post_lifetime_attrs = None; + let ty_param = p.parse_ty_param(attrs)?; if ty_param.default.is_some() { seen_default = true; } else if seen_default { - let last_span = p.last_span; - p.span_err(last_span, + let prev_span = p.prev_span; + p.span_err(prev_span, "type parameters with a default must be trailing"); } Ok(ty_param) })?; + if let Some(attrs) = post_lifetime_attrs { + if !attrs.is_empty() { + self.span_err(attrs[0].span, + "trailing attribute after lifetime parameters"); + } + } Ok(ast::Generics { lifetimes: lifetime_defs, ty_params: ty_params, @@ -4283,7 +4305,7 @@ impl<'a> Parser<'a> { id: ast::DUMMY_NODE_ID, predicates: Vec::new(), }, - span: mk_sp(span_lo, self.last_span.hi), + span: mk_sp(span_lo, self.prev_span.hi), }) } else { Ok(ast::Generics::default()) @@ -4298,7 +4320,7 @@ impl<'a> Parser<'a> { let missing_comma = !lifetimes.is_empty() && !self.token.is_like_gt() && - self.last_token_kind != LastTokenKind::Comma; + self.prev_token_kind != PrevTokenKind::Comma; if missing_comma { @@ -4377,7 +4399,7 @@ impl<'a> Parser<'a> { /// where T : Trait + 'b, 'a : 'b /// ``` pub fn parse_where_clause(&mut self) -> PResult<'a, ast::WhereClause> { - maybe_whole!(self, NtWhereClause); + maybe_whole!(self, NtWhereClause, |x| x); let mut where_clause = WhereClause { id: ast::DUMMY_NODE_ID, @@ -4405,7 +4427,7 @@ impl<'a> Parser<'a> { let bounds = self.parse_lifetimes(token::BinOp(token::Plus))?; - let hi = self.last_span.hi; + let hi = self.prev_span.hi; let span = mk_sp(lo, hi); where_clause.predicates.push(ast::WherePredicate::RegionPredicate( @@ -4423,7 +4445,7 @@ impl<'a> Parser<'a> { let bound_lifetimes = if self.eat_keyword(keywords::For) { // Higher ranked constraint. self.expect(&token::Lt)?; - let lifetime_defs = self.parse_lifetime_defs()?; + let lifetime_defs = self.parse_lifetime_defs(None)?; self.expect_gt()?; lifetime_defs } else { @@ -4434,7 +4456,7 @@ impl<'a> Parser<'a> { if self.eat(&token::Colon) { let bounds = self.parse_ty_param_bounds(BoundParsingMode::Bare)?; - let hi = self.last_span.hi; + let hi = self.prev_span.hi; let span = mk_sp(lo, hi); if bounds.is_empty() { @@ -4454,7 +4476,7 @@ impl<'a> Parser<'a> { parsed_something = true; } else if self.eat(&token::Eq) { // let ty = try!(self.parse_ty()); - let hi = self.last_span.hi; + let hi = self.prev_span.hi; let span = mk_sp(lo, hi); // where_clause.predicates.push( // ast::WherePredicate::EqPredicate(ast::WhereEqPredicate { @@ -4469,8 +4491,8 @@ impl<'a> Parser<'a> { "equality constraints are not yet supported \ in where clauses (#20041)"); } else { - let last_span = self.last_span; - self.span_err(last_span, + let prev_span = self.prev_span; + self.span_err(prev_span, "unexpected token in `where` clause"); } } @@ -4482,8 +4504,8 @@ impl<'a> Parser<'a> { } if !parsed_something { - let last_span = self.last_span; - self.span_err(last_span, + let prev_span = self.prev_span; + self.span_err(prev_span, "a `where` clause must have at least one predicate \ in it"); } @@ -4556,9 +4578,13 @@ impl<'a> Parser<'a> { fn parse_self_arg(&mut self) -> PResult<'a, Option> { let expect_ident = |this: &mut Self| match this.token { // Preserve hygienic context. - token::Ident(ident) => { this.bump(); codemap::respan(this.last_span, ident) } + token::Ident(ident) => { this.bump(); codemap::respan(this.prev_span, ident) } _ => unreachable!() }; + let isolated_self = |this: &mut Self, n| { + this.look_ahead(n, |t| t.is_keyword(keywords::SelfValue)) && + this.look_ahead(n + 1, |t| t != &token::ModSep) + }; // Parse optional self parameter of a method. // Only a limited set of initial token sequences is considered self parameters, anything @@ -4571,22 +4597,22 @@ impl<'a> Parser<'a> { // &'lt self // &'lt mut self // ¬_self - if self.look_ahead(1, |t| t.is_keyword(keywords::SelfValue)) { + if isolated_self(self, 1) { self.bump(); (SelfKind::Region(None, Mutability::Immutable), expect_ident(self)) } else if self.look_ahead(1, |t| t.is_keyword(keywords::Mut)) && - self.look_ahead(2, |t| t.is_keyword(keywords::SelfValue)) { + isolated_self(self, 2) { self.bump(); self.bump(); (SelfKind::Region(None, Mutability::Mutable), expect_ident(self)) } else if self.look_ahead(1, |t| t.is_lifetime()) && - self.look_ahead(2, |t| t.is_keyword(keywords::SelfValue)) { + isolated_self(self, 2) { self.bump(); let lt = self.parse_lifetime()?; (SelfKind::Region(Some(lt), Mutability::Immutable), expect_ident(self)) } else if self.look_ahead(1, |t| t.is_lifetime()) && self.look_ahead(2, |t| t.is_keyword(keywords::Mut)) && - self.look_ahead(3, |t| t.is_keyword(keywords::SelfValue)) { + isolated_self(self, 3) { self.bump(); let lt = self.parse_lifetime()?; self.bump(); @@ -4601,12 +4627,12 @@ impl<'a> Parser<'a> { // *mut self // *not_self // Emit special error for `self` cases. - if self.look_ahead(1, |t| t.is_keyword(keywords::SelfValue)) { + if isolated_self(self, 1) { self.bump(); self.span_err(self.span, "cannot pass `self` by raw pointer"); (SelfKind::Value(Mutability::Immutable), expect_ident(self)) } else if self.look_ahead(1, |t| t.is_mutability()) && - self.look_ahead(2, |t| t.is_keyword(keywords::SelfValue)) { + isolated_self(self, 2) { self.bump(); self.bump(); self.span_err(self.span, "cannot pass `self` by raw pointer"); @@ -4616,7 +4642,7 @@ impl<'a> Parser<'a> { } } token::Ident(..) => { - if self.token.is_keyword(keywords::SelfValue) { + if isolated_self(self, 0) { // self // self: TYPE let eself_ident = expect_ident(self); @@ -4627,7 +4653,7 @@ impl<'a> Parser<'a> { (SelfKind::Value(Mutability::Immutable), eself_ident) } } else if self.token.is_keyword(keywords::Mut) && - self.look_ahead(1, |t| t.is_keyword(keywords::SelfValue)) { + isolated_self(self, 1) { // mut self // mut self: TYPE self.bump(); @@ -4645,7 +4671,7 @@ impl<'a> Parser<'a> { _ => return Ok(None), }; - let eself = codemap::respan(mk_sp(eself_lo, self.last_span.hi), eself); + let eself = codemap::respan(mk_sp(eself_lo, self.prev_span.hi), eself); Ok(Some(Arg::from_self(eself, eself_ident))) } @@ -4763,7 +4789,7 @@ impl<'a> Parser<'a> { ast::Unsafety, abi::Abi)> { let is_const_fn = self.eat_keyword(keywords::Const); - let const_span = self.last_span; + let const_span = self.prev_span; let unsafety = self.parse_unsafety()?; let (constness, unsafety, abi) = if is_const_fn { (respan(const_span, Constness::Const), unsafety, Abi::Rust) @@ -4773,7 +4799,7 @@ impl<'a> Parser<'a> { } else { Abi::Rust }; - (respan(self.last_span, Constness::NotConst), unsafety, abi) + (respan(self.prev_span, Constness::NotConst), unsafety, abi) }; self.expect_keyword(keywords::Fn)?; Ok((constness, unsafety, abi)) @@ -4781,7 +4807,7 @@ impl<'a> Parser<'a> { /// Parse an impl item. pub fn parse_impl_item(&mut self) -> PResult<'a, ImplItem> { - maybe_whole!(no_clone_from_p self, NtImplItem); + maybe_whole!(self, NtImplItem, |x| x); let mut attrs = self.parse_outer_attributes()?; let lo = self.span.lo; @@ -4810,7 +4836,7 @@ impl<'a> Parser<'a> { Ok(ImplItem { id: ast::DUMMY_NODE_ID, - span: mk_sp(lo, self.last_span.hi), + span: mk_sp(lo, self.prev_span.hi), ident: name, vis: vis, defaultness: defaultness, @@ -4850,8 +4876,8 @@ impl<'a> Parser<'a> { if self.token.is_path_start() { // method macro. - let last_span = self.last_span; - self.complain_if_pub_macro(&vis, last_span); + let prev_span = self.prev_span; + self.complain_if_pub_macro(&vis, prev_span); let lo = self.span.lo; let pth = self.parse_path(PathStyle::Mod)?; @@ -4866,7 +4892,7 @@ impl<'a> Parser<'a> { self.expect(&token::Semi)? } - let mac = spanned(lo, self.last_span.hi, Mac_ { path: pth, tts: tts }); + let mac = spanned(lo, self.prev_span.hi, Mac_ { path: pth, tts: tts }); Ok((keywords::Invalid.ident(), vec![], ast::ImplItemKind::Macro(mac))) } else { let (constness, unsafety, abi) = self.parse_fn_front_matter()?; @@ -4991,7 +5017,7 @@ impl<'a> Parser<'a> { fn parse_late_bound_lifetime_defs(&mut self) -> PResult<'a, Vec> { if self.eat_keyword(keywords::For) { self.expect(&token::Lt)?; - let lifetime_defs = self.parse_lifetime_defs()?; + let lifetime_defs = self.parse_lifetime_defs(None)?; self.expect_gt()?; Ok(lifetime_defs) } else { @@ -5007,7 +5033,7 @@ impl<'a> Parser<'a> { Ok(ast::PolyTraitRef { bound_lifetimes: lifetime_defs, trait_ref: self.parse_trait_ref()?, - span: mk_sp(lo, self.last_span.hi), + span: mk_sp(lo, self.prev_span.hi), }) } @@ -5083,7 +5109,11 @@ impl<'a> Parser<'a> { let mut fields = Vec::new(); if self.eat(&token::OpenDelim(token::Brace)) { while self.token != token::CloseDelim(token::Brace) { - fields.push(self.parse_struct_decl_field()?); + fields.push(self.parse_struct_decl_field().map_err(|e| { + self.recover_stmt(); + self.eat(&token::CloseDelim(token::Brace)); + e + })?); } self.bump(); @@ -5173,7 +5203,7 @@ impl<'a> Parser<'a> { // If `allow_path` is false, just parse the `pub` in `pub(path)` (but still parse `pub(crate)`) fn parse_visibility(&mut self, allow_path: bool) -> PResult<'a, Visibility> { let pub_crate = |this: &mut Self| { - let span = this.last_span; + let span = this.prev_span; this.expect(&token::CloseDelim(token::Paren))?; Ok(Visibility::Crate(span)) }; @@ -5224,7 +5254,7 @@ impl<'a> Parser<'a> { let hi = if self.span == syntax_pos::DUMMY_SP { inner_lo } else { - self.last_span.hi + self.prev_span.hi }; Ok(ast::Mod { @@ -5251,7 +5281,6 @@ impl<'a> Parser<'a> { fn parse_item_mod(&mut self, outer_attrs: &[Attribute]) -> PResult<'a, ItemInfo> { let (in_cfg, outer_attrs) = { let mut strip_unconfigured = ::config::StripUnconfigured { - config: &self.cfg, sess: self.sess, should_test: false, // irrelevant features: None, // don't perform gated feature checking @@ -5274,23 +5303,27 @@ impl<'a> Parser<'a> { } } else { let directory = self.directory.clone(); - self.push_directory(id, &outer_attrs); + let restrictions = self.push_directory(id, &outer_attrs); self.expect(&token::OpenDelim(token::Brace))?; let mod_inner_lo = self.span.lo; let attrs = self.parse_inner_attributes()?; - let m = self.parse_mod_items(&token::CloseDelim(token::Brace), mod_inner_lo)?; + let m = self.with_res(restrictions, |this| { + this.parse_mod_items(&token::CloseDelim(token::Brace), mod_inner_lo) + })?; self.directory = directory; Ok((id, ItemKind::Mod(m), Some(attrs))) } } - fn push_directory(&mut self, id: Ident, attrs: &[Attribute]) { - let default_path = self.id_to_interned_str(id); - let file_path = match ::attr::first_attr_value_str_by_name(attrs, "path") { - Some(d) => d, - None => default_path, - }; - self.directory.push(&*file_path) + fn push_directory(&mut self, id: Ident, attrs: &[Attribute]) -> Restrictions { + if let Some(path) = ::attr::first_attr_value_str_by_name(attrs, "path") { + self.directory.push(&*path); + self.restrictions - Restrictions::NO_NONINLINE_MOD + } else { + let default_path = self.id_to_interned_str(id); + self.directory.push(&*default_path); + self.restrictions + } } pub fn submod_path_from_attr(attrs: &[ast::Attribute], dir_path: &Path) -> Option { @@ -5415,12 +5448,7 @@ impl<'a> Parser<'a> { included_mod_stack.push(path.clone()); drop(included_mod_stack); - let mut p0 = new_sub_parser_from_file(self.sess, - self.cfg.clone(), - &path, - owns_directory, - Some(name), - id_sp); + let mut p0 = new_sub_parser_from_file(self.sess, &path, owns_directory, Some(name), 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)?; @@ -5489,9 +5517,9 @@ impl<'a> Parser<'a> { }; self.expect(&token::Semi)?; - let last_span = self.last_span; + let prev_span = self.prev_span; Ok(self.mk_item(lo, - last_span.hi, + prev_span.hi, ident, ItemKind::ExternCrate(maybe_path), visibility, @@ -5526,13 +5554,13 @@ impl<'a> Parser<'a> { } self.expect(&token::CloseDelim(token::Brace))?; - let last_span = self.last_span; + let prev_span = self.prev_span; let m = ast::ForeignMod { abi: abi, items: foreign_items }; Ok(self.mk_item(lo, - last_span.hi, + prev_span.hi, keywords::Invalid.ident(), ItemKind::ForeignMod(m), visibility, @@ -5585,7 +5613,7 @@ impl<'a> Parser<'a> { data: struct_def, disr_expr: disr_expr, }; - variants.push(spanned(vlo, self.last_span.hi, vr)); + variants.push(spanned(vlo, self.prev_span.hi, vr)); if !self.eat(&token::Comma) { break; } } @@ -5607,7 +5635,11 @@ impl<'a> Parser<'a> { generics.where_clause = self.parse_where_clause()?; self.expect(&token::OpenDelim(token::Brace))?; - let enum_definition = self.parse_enum_def(&generics)?; + let enum_definition = self.parse_enum_def(&generics).map_err(|e| { + self.recover_stmt(); + self.eat(&token::CloseDelim(token::Brace)); + e + })?; Ok((id, ItemKind::Enum(enum_definition, generics), None)) } @@ -5622,9 +5654,9 @@ impl<'a> Parser<'a> { match abi::lookup(&s.as_str()) { Some(abi) => Ok(Some(abi)), None => { - let last_span = self.last_span; + let prev_span = self.prev_span; self.span_err( - last_span, + prev_span, &format!("invalid ABI: expected one of [{}], \ found `{}`", abi::all_names().join(", "), @@ -5643,19 +5675,13 @@ impl<'a> Parser<'a> { /// extern crate. fn parse_item_(&mut self, attrs: Vec, macros_allowed: bool, attributes_allowed: bool) -> PResult<'a, Option>> { - let nt_item = match self.token { - token::Interpolated(token::NtItem(ref item)) => { - Some((**item).clone()) - } - _ => None - }; - if let Some(mut item) = nt_item { - self.bump(); + maybe_whole!(self, NtItem, |item| { + let mut item = item.unwrap(); let mut attrs = attrs; mem::swap(&mut item.attrs, &mut attrs); item.attrs.extend(attrs); - return Ok(Some(P(item))); - } + Some(P(item)) + }); let lo = self.span.lo; @@ -5666,9 +5692,9 @@ impl<'a> Parser<'a> { let item_ = ItemKind::Use(self.parse_view_path()?); self.expect(&token::Semi)?; - let last_span = self.last_span; + let prev_span = self.prev_span; let item = self.mk_item(lo, - last_span.hi, + prev_span.hi, keywords::Invalid.ident(), item_, visibility, @@ -5685,15 +5711,15 @@ impl<'a> Parser<'a> { if self.eat_keyword(keywords::Fn) { // EXTERN FUNCTION ITEM - let fn_span = self.last_span; + let fn_span = self.prev_span; let abi = opt_abi.unwrap_or(Abi::C); let (ident, item_, extra_attrs) = self.parse_item_fn(Unsafety::Normal, respan(fn_span, Constness::NotConst), abi)?; - let last_span = self.last_span; + let prev_span = self.prev_span; let item = self.mk_item(lo, - last_span.hi, + prev_span.hi, ident, item_, visibility, @@ -5714,9 +5740,9 @@ impl<'a> Parser<'a> { Mutability::Immutable }; let (ident, item_, extra_attrs) = self.parse_item_const(Some(m))?; - let last_span = self.last_span; + let prev_span = self.prev_span; let item = self.mk_item(lo, - last_span.hi, + prev_span.hi, ident, item_, visibility, @@ -5724,7 +5750,7 @@ impl<'a> Parser<'a> { return Ok(Some(item)); } if self.eat_keyword(keywords::Const) { - let const_span = self.last_span; + let const_span = self.prev_span; if self.check_keyword(keywords::Fn) || (self.check_keyword(keywords::Unsafe) && self.look_ahead(1, |t| t.is_keyword(keywords::Fn))) { @@ -5739,9 +5765,9 @@ impl<'a> Parser<'a> { self.parse_item_fn(unsafety, respan(const_span, Constness::Const), Abi::Rust)?; - let last_span = self.last_span; + let prev_span = self.prev_span; let item = self.mk_item(lo, - last_span.hi, + prev_span.hi, ident, item_, visibility, @@ -5751,15 +5777,15 @@ impl<'a> Parser<'a> { // CONST ITEM if self.eat_keyword(keywords::Mut) { - let last_span = self.last_span; - self.diagnostic().struct_span_err(last_span, "const globals cannot be mutable") + let prev_span = self.prev_span; + self.diagnostic().struct_span_err(prev_span, "const globals cannot be mutable") .help("did you mean to declare a static?") .emit(); } let (ident, item_, extra_attrs) = self.parse_item_const(None)?; - let last_span = self.last_span; + let prev_span = self.prev_span; let item = self.mk_item(lo, - last_span.hi, + prev_span.hi, ident, item_, visibility, @@ -5774,9 +5800,9 @@ impl<'a> Parser<'a> { self.expect_keyword(keywords::Trait)?; let (ident, item_, extra_attrs) = self.parse_item_trait(ast::Unsafety::Unsafe)?; - let last_span = self.last_span; + let prev_span = self.prev_span; let item = self.mk_item(lo, - last_span.hi, + prev_span.hi, ident, item_, visibility, @@ -5790,9 +5816,9 @@ impl<'a> Parser<'a> { self.expect_keyword(keywords::Unsafe)?; self.expect_keyword(keywords::Impl)?; let (ident, item_, extra_attrs) = self.parse_item_impl(ast::Unsafety::Unsafe)?; - let last_span = self.last_span; + let prev_span = self.prev_span; let item = self.mk_item(lo, - last_span.hi, + prev_span.hi, ident, item_, visibility, @@ -5802,14 +5828,14 @@ impl<'a> Parser<'a> { if self.check_keyword(keywords::Fn) { // FUNCTION ITEM self.bump(); - let fn_span = self.last_span; + let fn_span = self.prev_span; let (ident, item_, extra_attrs) = self.parse_item_fn(Unsafety::Normal, respan(fn_span, Constness::NotConst), Abi::Rust)?; - let last_span = self.last_span; + let prev_span = self.prev_span; let item = self.mk_item(lo, - last_span.hi, + prev_span.hi, ident, item_, visibility, @@ -5826,14 +5852,14 @@ impl<'a> Parser<'a> { Abi::Rust }; self.expect_keyword(keywords::Fn)?; - let fn_span = self.last_span; + let fn_span = self.prev_span; let (ident, item_, extra_attrs) = self.parse_item_fn(Unsafety::Unsafe, respan(fn_span, Constness::NotConst), abi)?; - let last_span = self.last_span; + let prev_span = self.prev_span; let item = self.mk_item(lo, - last_span.hi, + prev_span.hi, ident, item_, visibility, @@ -5844,9 +5870,9 @@ impl<'a> Parser<'a> { // MODULE ITEM let (ident, item_, extra_attrs) = self.parse_item_mod(&attrs[..])?; - let last_span = self.last_span; + let prev_span = self.prev_span; let item = self.mk_item(lo, - last_span.hi, + prev_span.hi, ident, item_, visibility, @@ -5856,9 +5882,9 @@ impl<'a> Parser<'a> { if self.eat_keyword(keywords::Type) { // TYPE ITEM let (ident, item_, extra_attrs) = self.parse_item_type()?; - let last_span = self.last_span; + let prev_span = self.prev_span; let item = self.mk_item(lo, - last_span.hi, + prev_span.hi, ident, item_, visibility, @@ -5868,9 +5894,9 @@ impl<'a> Parser<'a> { if self.eat_keyword(keywords::Enum) { // ENUM ITEM let (ident, item_, extra_attrs) = self.parse_item_enum()?; - let last_span = self.last_span; + let prev_span = self.prev_span; let item = self.mk_item(lo, - last_span.hi, + prev_span.hi, ident, item_, visibility, @@ -5881,9 +5907,9 @@ impl<'a> Parser<'a> { // TRAIT ITEM let (ident, item_, extra_attrs) = self.parse_item_trait(ast::Unsafety::Normal)?; - let last_span = self.last_span; + let prev_span = self.prev_span; let item = self.mk_item(lo, - last_span.hi, + prev_span.hi, ident, item_, visibility, @@ -5893,9 +5919,9 @@ impl<'a> Parser<'a> { if self.eat_keyword(keywords::Impl) { // IMPL ITEM let (ident, item_, extra_attrs) = self.parse_item_impl(ast::Unsafety::Normal)?; - let last_span = self.last_span; + let prev_span = self.prev_span; let item = self.mk_item(lo, - last_span.hi, + prev_span.hi, ident, item_, visibility, @@ -5905,23 +5931,22 @@ impl<'a> Parser<'a> { if self.eat_keyword(keywords::Struct) { // STRUCT ITEM let (ident, item_, extra_attrs) = self.parse_item_struct()?; - let last_span = self.last_span; + let prev_span = self.prev_span; let item = self.mk_item(lo, - last_span.hi, + prev_span.hi, ident, item_, visibility, maybe_append(attrs, extra_attrs)); return Ok(Some(item)); } - if self.check_keyword(keywords::Union) && - self.look_ahead(1, |t| t.is_ident() && !t.is_any_keyword()) { + if self.is_union_item() { // UNION ITEM self.bump(); let (ident, item_, extra_attrs) = self.parse_item_union()?; - let last_span = self.last_span; + let prev_span = self.prev_span; let item = self.mk_item(lo, - last_span.hi, + prev_span.hi, ident, item_, visibility, @@ -5967,8 +5992,8 @@ impl<'a> Parser<'a> { if macros_allowed && self.token.is_path_start() { // MACRO INVOCATION ITEM - let last_span = self.last_span; - self.complain_if_pub_macro(&visibility, last_span); + let prev_span = self.prev_span; + self.complain_if_pub_macro(&visibility, prev_span); let mac_lo = self.span.lo; @@ -5991,15 +6016,15 @@ impl<'a> Parser<'a> { |p| p.parse_token_tree())?; if delim != token::Brace { if !self.eat(&token::Semi) { - let last_span = self.last_span; - self.span_err(last_span, + let prev_span = self.prev_span; + self.span_err(prev_span, "macros that expand to items must either \ be surrounded with braces or followed by \ a semicolon"); } } - let hi = self.last_span.hi; + let hi = self.prev_span.hi; let mac = spanned(mac_lo, hi, Mac_ { path: pth, tts: tts }); let item = self.mk_item(lo, hi, id, ItemKind::Mac(mac), visibility, attrs); return Ok(Some(item)); @@ -6009,8 +6034,8 @@ impl<'a> Parser<'a> { match visibility { Visibility::Inherited => {} _ => { - let last_span = self.last_span; - return Err(self.span_fatal(last_span, "unmatched visibility `pub`")); + let prev_span = self.prev_span; + return Err(self.span_fatal(prev_span, "unmatched visibility `pub`")); } } @@ -6041,7 +6066,7 @@ impl<'a> Parser<'a> { rename: rename, id: ast::DUMMY_NODE_ID }; - let hi = this.last_span.hi; + let hi = this.prev_span.hi; Ok(spanned(lo, hi, node)) }) } @@ -6061,15 +6086,20 @@ impl<'a> Parser<'a> { /// MOD_SEP? LBRACE item_seq RBRACE fn parse_view_path(&mut self) -> PResult<'a, P> { let lo = self.span.lo; - if self.check(&token::OpenDelim(token::Brace)) || self.is_import_coupler() { - // `{foo, bar}` or `::{foo, bar}` + if self.check(&token::OpenDelim(token::Brace)) || self.check(&token::BinOp(token::Star)) || + self.is_import_coupler() { + // `{foo, bar}`, `::{foo, bar}`, `*`, or `::*`. let prefix = ast::Path { global: self.eat(&token::ModSep), segments: Vec::new(), span: mk_sp(lo, self.span.hi), }; - let items = self.parse_path_list_items()?; - Ok(P(spanned(lo, self.span.hi, ViewPathList(prefix, items)))) + let view_path_kind = if self.eat(&token::BinOp(token::Star)) { + ViewPathGlob(prefix) + } else { + ViewPathList(prefix, self.parse_path_list_items()?) + }; + Ok(P(spanned(lo, self.span.hi, view_path_kind))) } else { let prefix = self.parse_path(PathStyle::Mod)?; if self.is_import_coupler() { @@ -6086,7 +6116,7 @@ impl<'a> Parser<'a> { // `foo::bar` or `foo::bar as baz` let rename = self.parse_rename()?. unwrap_or(prefix.segments.last().unwrap().identifier); - Ok(P(spanned(lo, self.last_span.hi, ViewPathSimple(rename, prefix)))) + Ok(P(spanned(lo, self.prev_span.hi, ViewPathSimple(rename, prefix)))) } } } @@ -6106,7 +6136,6 @@ impl<'a> Parser<'a> { Ok(ast::Crate { attrs: self.parse_inner_attributes()?, module: self.parse_mod_items(&token::Eof, lo)?, - config: self.cfg.clone(), span: mk_sp(lo, self.span.lo), exported_macros: Vec::new(), }) @@ -6134,7 +6163,7 @@ impl<'a> Parser<'a> { pub fn parse_str(&mut self) -> PResult<'a, (InternedString, StrStyle)> { match self.parse_optional_str() { Some((s, style, suf)) => { - let sp = self.last_span; + let sp = self.prev_span; self.expect_no_suffix(sp, "string literal", suf); Ok((s, style)) } diff --git a/src/libsyntax/parse/token.rs b/src/libsyntax/parse/token.rs index 09bc560794..0198ee073d 100644 --- a/src/libsyntax/parse/token.rs +++ b/src/libsyntax/parse/token.rs @@ -52,21 +52,6 @@ pub enum DelimToken { NoDelim, } -#[derive(Clone, RustcEncodable, RustcDecodable, PartialEq, Eq, Hash, Debug, Copy)] -pub enum SpecialMacroVar { - /// `$crate` will be filled in with the name of the crate a macro was - /// imported from, if any. - CrateMacroVar, -} - -impl SpecialMacroVar { - pub fn as_str(self) -> &'static str { - match self { - SpecialMacroVar::CrateMacroVar => "crate", - } - } -} - #[derive(Clone, RustcEncodable, RustcDecodable, PartialEq, Eq, Hash, Debug, Copy)] pub enum Lit { Byte(ast::Name), @@ -138,7 +123,7 @@ pub enum Token { Lifetime(ast::Ident), /* For interpolation */ - Interpolated(Nonterminal), + Interpolated(Rc), // Can be expanded into several tokens. /// Doc comment DocComment(ast::Name), @@ -148,8 +133,6 @@ pub enum Token { // In right-hand-sides of MBE macros: /// A syntactic variable that will be filled in by macro expansion. SubstNt(ast::Ident), - /// A macro variable with special meaning. - SpecialVarNt(SpecialMacroVar), // Junk. These carry no data because we don't really care about the data // they *would* carry, and don't really want to allocate a new ident for @@ -176,10 +159,8 @@ impl Token { /// Returns `true` if the token can appear at the start of an expression. pub fn can_begin_expr(&self) -> bool { match *self { - OpenDelim(_) => true, + OpenDelim(..) => true, Ident(..) => true, - Underscore => true, - Tilde => true, Literal(..) => true, Not => true, BinOp(Minus) => true, @@ -189,13 +170,17 @@ impl Token { OrOr => true, // in lambda syntax AndAnd => true, // double borrow DotDot | DotDotDot => true, // range notation + Lt | BinOp(Shl) => true, // associated path ModSep => true, - Interpolated(NtExpr(..)) => true, - Interpolated(NtIdent(..)) => true, - Interpolated(NtBlock(..)) => true, - Interpolated(NtPath(..)) => true, Pound => true, // for expression attributes - _ => false, + Interpolated(ref nt) => match **nt { + NtExpr(..) => true, + NtIdent(..) => true, + NtBlock(..) => true, + NtPath(..) => true, + _ => false, + }, + _ => false, } } @@ -233,10 +218,12 @@ impl Token { /// Returns `true` if the token is an interpolated path. pub fn is_path(&self) -> bool { - match *self { - Interpolated(NtPath(..)) => true, - _ => false, + if let Interpolated(ref nt) = *self { + if let NtPath(..) = **nt { + return true; + } } + false } /// Returns `true` if the token is a lifetime. @@ -253,8 +240,12 @@ impl Token { self.is_keyword(keywords::Const) } + pub fn is_qpath_start(&self) -> bool { + self == &Lt || self == &BinOp(Shl) + } + pub fn is_path_start(&self) -> bool { - self == &ModSep || self == &Lt || self.is_path() || + self == &ModSep || self.is_qpath_start() || self.is_path() || self.is_path_segment_keyword() || self.is_ident() && !self.is_any_keyword() } @@ -304,19 +295,19 @@ impl Token { pub enum Nonterminal { NtItem(P), NtBlock(P), - NtStmt(P), + NtStmt(ast::Stmt), NtPat(P), NtExpr(P), NtTy(P), - NtIdent(Box), + NtIdent(ast::SpannedIdent), /// Stuff inside brackets for attributes NtMeta(P), - NtPath(Box), - NtTT(P), // needs P'ed to break a circularity + NtPath(ast::Path), + NtTT(tokenstream::TokenTree), // These are not exposed to macros, but are used by quasiquote. NtArm(ast::Arm), - NtImplItem(P), - NtTraitItem(P), + NtImplItem(ast::ImplItem), + NtTraitItem(ast::TraitItem), NtGenerics(ast::Generics), NtWhereClause(ast::WhereClause), NtArg(ast::Arg), @@ -478,27 +469,20 @@ pub fn clear_ident_interner() { /// somehow. #[derive(Clone, PartialEq, Hash, PartialOrd, Eq, Ord)] pub struct InternedString { - string: Rc, + string: Rc, } impl InternedString { #[inline] pub fn new(string: &'static str) -> InternedString { InternedString { - string: Rc::new(string.to_owned()), - } - } - - #[inline] - fn new_from_rc_str(string: Rc) -> InternedString { - InternedString { - string: string, + string: Rc::__from_str(string), } } #[inline] pub fn new_from_name(name: ast::Name) -> InternedString { - with_ident_interner(|interner| InternedString::new_from_rc_str(interner.get(name))) + with_ident_interner(|interner| InternedString { string: interner.get(name) }) } } @@ -566,7 +550,7 @@ impl PartialEq for str { impl Decodable for InternedString { fn decode(d: &mut D) -> Result { - Ok(intern(d.read_str()?.as_ref()).as_str()) + Ok(intern(&d.read_str()?).as_str()) } } diff --git a/src/libsyntax/print/pp.rs b/src/libsyntax/print/pp.rs index 32b66da4d9..792239e721 100644 --- a/src/libsyntax/print/pp.rs +++ b/src/libsyntax/print/pp.rs @@ -125,9 +125,8 @@ impl fmt::Display for Token { } } -fn buf_str(toks: &[Token], szs: &[isize], left: usize, right: usize, lim: usize) -> String { - let n = toks.len(); - assert_eq!(n, szs.len()); +fn buf_str(buf: &[BufEntry], left: usize, right: usize, lim: usize) -> String { + let n = buf.len(); let mut i = left; let mut l = lim; let mut s = String::from("["); @@ -136,7 +135,7 @@ fn buf_str(toks: &[Token], szs: &[isize], left: usize, right: usize, lim: usize) if i != left { s.push_str(", "); } - s.push_str(&format!("{}={}", szs[i], &toks[i])); + s.push_str(&format!("{}={}", buf[i].size, &buf[i].token)); i += 1; i %= n; } @@ -159,13 +158,9 @@ pub struct PrintStackElem { const SIZE_INFINITY: isize = 0xffff; pub fn mk_printer<'a>(out: Box, linewidth: usize) -> Printer<'a> { - // Yes 55, it makes the ring buffers big enough to never - // fall behind. + // Yes 55, it makes the ring buffers big enough to never fall behind. let n: usize = 55 * linewidth; debug!("mk_printer {}", linewidth); - let token = vec![Token::Eof; n]; - let size = vec![0; n]; - let scan_stack = VecDeque::with_capacity(n); Printer { out: out, buf_len: n, @@ -173,11 +168,10 @@ pub fn mk_printer<'a>(out: Box, linewidth: usize) -> Printer<'a> { space: linewidth as isize, left: 0, right: 0, - token: token, - size: size, + buf: vec![BufEntry { token: Token::Eof, size: 0 }; n], left_total: 0, right_total: 0, - scan_stack: scan_stack, + scan_stack: VecDeque::new(), print_stack: Vec::new(), pending_indentation: 0 } @@ -269,10 +263,8 @@ pub struct Printer<'a> { left: usize, /// Index of right side of input stream right: usize, - /// Ring-buffer stream goes through - token: Vec , - /// Ring-buffer of calculated sizes - size: Vec , + /// Ring-buffer of tokens and calculated sizes + buf: Vec, /// Running size of stream "...left" left_total: isize, /// Running size of stream "...right" @@ -283,20 +275,26 @@ pub struct Printer<'a> { /// Begin (if there is any) on top of it. Stuff is flushed off the /// bottom as it becomes irrelevant due to the primary ring-buffer /// advancing. - scan_stack: VecDeque , + scan_stack: VecDeque, /// Stack of blocks-in-progress being flushed by print print_stack: Vec , /// Buffered indentation to avoid writing trailing whitespace pending_indentation: isize, } +#[derive(Clone)] +struct BufEntry { + token: Token, + size: isize, +} + impl<'a> Printer<'a> { pub fn last_token(&mut self) -> Token { - self.token[self.right].clone() + self.buf[self.right].token.clone() } // be very careful with this! pub fn replace_last_token(&mut self, t: Token) { - self.token[self.right] = t; + self.buf[self.right].token = t; } pub fn pretty_print(&mut self, token: Token) -> io::Result<()> { debug!("pp Vec<{},{}>", self.left, self.right); @@ -318,8 +316,7 @@ impl<'a> Printer<'a> { } else { self.advance_right(); } debug!("pp Begin({})/buffer Vec<{},{}>", b.offset, self.left, self.right); - self.token[self.right] = token; - self.size[self.right] = -self.right_total; + self.buf[self.right] = BufEntry { token: token, size: -self.right_total }; let right = self.right; self.scan_push(right); Ok(()) @@ -331,8 +328,7 @@ impl<'a> Printer<'a> { } else { debug!("pp End/buffer Vec<{},{}>", self.left, self.right); self.advance_right(); - self.token[self.right] = token; - self.size[self.right] = -1; + self.buf[self.right] = BufEntry { token: token, size: -1 }; let right = self.right; self.scan_push(right); Ok(()) @@ -350,8 +346,7 @@ impl<'a> Printer<'a> { self.check_stack(0); let right = self.right; self.scan_push(right); - self.token[self.right] = token; - self.size[self.right] = -self.right_total; + self.buf[self.right] = BufEntry { token: token, size: -self.right_total }; self.right_total += b.blank_space; Ok(()) } @@ -364,8 +359,7 @@ impl<'a> Printer<'a> { debug!("pp String('{}')/buffer Vec<{},{}>", s, self.left, self.right); self.advance_right(); - self.token[self.right] = Token::String(s, len); - self.size[self.right] = len; + self.buf[self.right] = BufEntry { token: Token::String(s, len), size: len }; self.right_total += len; self.check_stream() } @@ -381,7 +375,7 @@ impl<'a> Printer<'a> { if Some(&self.left) == self.scan_stack.back() { debug!("setting {} to infinity and popping", self.left); let scanned = self.scan_pop_bottom(); - self.size[scanned] = SIZE_INFINITY; + self.buf[scanned].size = SIZE_INFINITY; } self.advance_left()?; if self.left != self.right { @@ -410,12 +404,12 @@ impl<'a> Printer<'a> { } pub fn advance_left(&mut self) -> io::Result<()> { debug!("advance_left Vec<{},{}>, sizeof({})={}", self.left, self.right, - self.left, self.size[self.left]); + self.left, self.buf[self.left].size); - let mut left_size = self.size[self.left]; + let mut left_size = self.buf[self.left].size; while left_size >= 0 { - let left = self.token[self.left].clone(); + let left = self.buf[self.left].token.clone(); let len = match left { Token::Break(b) => b.blank_space, @@ -437,7 +431,7 @@ impl<'a> Printer<'a> { self.left += 1; self.left %= self.buf_len; - left_size = self.size[self.left]; + left_size = self.buf[self.left].size; } Ok(()) @@ -445,23 +439,23 @@ impl<'a> Printer<'a> { pub fn check_stack(&mut self, k: isize) { if !self.scan_stack.is_empty() { let x = self.scan_top(); - match self.token[x] { + match self.buf[x].token { Token::Begin(_) => { if k > 0 { let popped = self.scan_pop(); - self.size[popped] = self.size[x] + self.right_total; + self.buf[popped].size = self.buf[x].size + self.right_total; self.check_stack(k - 1); } } Token::End => { // paper says + not =, but that makes no sense. let popped = self.scan_pop(); - self.size[popped] = 1; + self.buf[popped].size = 1; self.check_stack(k + 1); } _ => { let popped = self.scan_pop(); - self.size[popped] = self.size[x] + self.right_total; + self.buf[popped].size = self.buf[x].size + self.right_total; if k > 0 { self.check_stack(k); } @@ -499,8 +493,7 @@ impl<'a> Printer<'a> { pub fn print(&mut self, token: Token, l: isize) -> io::Result<()> { debug!("print {} {} (remaining line space={})", token, l, self.space); - debug!("{}", buf_str(&self.token, - &self.size, + debug!("{}", buf_str(&self.buf, self.left, self.right, 6)); diff --git a/src/libsyntax/print/pprust.rs b/src/libsyntax/print/pprust.rs index 8563d27908..7352792a8a 100644 --- a/src/libsyntax/print/pprust.rs +++ b/src/libsyntax/print/pprust.rs @@ -112,7 +112,7 @@ pub fn print_crate<'a>(cm: &'a CodeMap, out, ann, is_expanded); - if is_expanded && !std_inject::no_std(krate) { + if is_expanded && !std_inject::injected_crate_name(krate).is_none() { // We need to print `#![no_std]` (and its feature gate) so that // compiling pretty-printed source won't inject libstd again. // However we don't want these attributes in the AST because @@ -285,9 +285,7 @@ pub fn token_to_string(tok: &Token) -> String { token::Comment => "/* */".to_string(), token::Shebang(s) => format!("/* shebang: {}*/", s), - token::SpecialVarNt(var) => format!("${}", var.as_str()), - - token::Interpolated(ref nt) => match *nt { + token::Interpolated(ref nt) => match **nt { token::NtExpr(ref e) => expr_to_string(&e), token::NtMeta(ref e) => meta_item_to_string(&e), token::NtTy(ref e) => ty_to_string(&e), @@ -545,15 +543,12 @@ pub trait PrintState<'a> { } fn maybe_print_comment(&mut self, pos: BytePos) -> io::Result<()> { - loop { - match self.next_comment() { - Some(ref cmnt) => { - if (*cmnt).pos < pos { - try!(self.print_comment(cmnt)); - self.cur_cmnt_and_lit().cur_cmnt += 1; - } else { break; } - } - _ => break + while let Some(ref cmnt) = self.next_comment() { + if cmnt.pos < pos { + try!(self.print_comment(cmnt)); + self.cur_cmnt_and_lit().cur_cmnt += 1; + } else { + break } } Ok(()) @@ -581,7 +576,9 @@ pub trait PrintState<'a> { Ok(()) } comments::Trailing => { - try!(word(self.writer(), " ")); + if !self.is_bol() { + try!(word(self.writer(), " ")); + } if cmnt.lines.len() == 1 { try!(word(self.writer(), &cmnt.lines[0])); hardbreak(self.writer()) @@ -972,7 +969,7 @@ impl<'a> State<'a> { try!(self.maybe_print_comment(ty.span.lo)); try!(self.ibox(0)); match ty.node { - ast::TyKind::Vec(ref ty) => { + ast::TyKind::Slice(ref ty) => { try!(word(&mut self.s, "[")); try!(self.print_type(&ty)); try!(word(&mut self.s, "]")); @@ -1039,7 +1036,7 @@ impl<'a> State<'a> { ast::TyKind::ImplTrait(ref bounds) => { try!(self.print_bounds("impl ", &bounds[..])); } - ast::TyKind::FixedLengthVec(ref ty, ref v) => { + ast::TyKind::Array(ref ty, ref v) => { try!(word(&mut self.s, "[")); try!(self.print_type(&ty)); try!(word(&mut self.s, "; ")); @@ -1361,6 +1358,7 @@ impl<'a> State<'a> { if comma { try!(self.word_space(",")) } + try!(self.print_outer_attributes_inline(&lifetime_def.attrs)); try!(self.print_lifetime_bounds(&lifetime_def.lifetime, &lifetime_def.bounds)); comma = true; } @@ -1715,6 +1713,7 @@ impl<'a> State<'a> { for (i, st) in blk.stmts.iter().enumerate() { match st.node { ast::StmtKind::Expr(ref expr) if i == blk.stmts.len() - 1 => { + try!(self.maybe_print_comment(st.span.lo)); try!(self.space_if_not_bol()); try!(self.print_expr_outer_attr_style(&expr, false)); try!(self.maybe_print_trailing_comment(expr.span, Some(blk.span.hi))); @@ -1894,8 +1893,10 @@ impl<'a> State<'a> { &fields[..], |s, field| { try!(s.ibox(INDENT_UNIT)); - try!(s.print_ident(field.ident.node)); - try!(s.word_space(":")); + if !field.is_shorthand { + try!(s.print_ident(field.ident.node)); + try!(s.word_space(":")); + } try!(s.print_expr(&field.expr)); s.end() }, @@ -2276,7 +2277,7 @@ impl<'a> State<'a> { Ok(()) })); - let mut options = vec!(); + let mut options = vec![]; if a.volatile { options.push("volatile"); } @@ -2450,13 +2451,10 @@ impl<'a> State<'a> { |s, ty| s.print_type(&ty))); try!(word(&mut self.s, ")")); - match data.output { - None => { } - Some(ref ty) => { - try!(self.space_if_not_bol()); - try!(self.word_space("->")); - try!(self.print_type(&ty)); - } + if let Some(ref ty) = data.output { + try!(self.space_if_not_bol()); + try!(self.word_space("->")); + try!(self.print_type(&ty)); } } } @@ -2573,7 +2571,7 @@ impl<'a> State<'a> { try!(word(&mut self.s, "...")); try!(self.print_expr(&end)); } - PatKind::Vec(ref before, ref slice, ref after) => { + PatKind::Slice(ref before, ref slice, ref after) => { try!(word(&mut self.s, "[")); try!(self.commasep(Inconsistent, &before[..], @@ -2604,6 +2602,7 @@ impl<'a> State<'a> { } try!(self.cbox(INDENT_UNIT)); try!(self.ibox(0)); + try!(self.maybe_print_comment(arm.pats[0].span.lo)); try!(self.print_outer_attributes(&arm.attrs)); let mut first = true; for p in &arm.pats { @@ -2803,6 +2802,7 @@ impl<'a> State<'a> { try!(self.commasep(Inconsistent, &ints[..], |s, &idx| { if idx < generics.lifetimes.len() { let lifetime_def = &generics.lifetimes[idx]; + try!(s.print_outer_attributes_inline(&lifetime_def.attrs)); s.print_lifetime_bounds(&lifetime_def.lifetime, &lifetime_def.bounds) } else { let idx = idx - generics.lifetimes.len(); @@ -2816,6 +2816,7 @@ impl<'a> State<'a> { } pub fn print_ty_param(&mut self, param: &ast::TyParam) -> io::Result<()> { + try!(self.print_outer_attributes_inline(¶m.attrs)); try!(self.print_ident(param.ident)); try!(self.print_bounds(":", ¶m.bounds)); match param.default { @@ -3007,15 +3008,11 @@ impl<'a> State<'a> { _ => return Ok(()) }; if let Some(ref cmnt) = self.next_comment() { - if (*cmnt).style != comments::Trailing { return Ok(()) } + if cmnt.style != comments::Trailing { return Ok(()) } let span_line = cm.lookup_char_pos(span.hi); - let comment_line = cm.lookup_char_pos((*cmnt).pos); - let mut next = (*cmnt).pos + BytePos(1); - if let Some(p) = next_pos { - next = p; - } - if span.hi < (*cmnt).pos && (*cmnt).pos < next && - span_line.line == comment_line.line { + let comment_line = cm.lookup_char_pos(cmnt.pos); + let next = next_pos.unwrap_or(cmnt.pos + BytePos(1)); + if span.hi < cmnt.pos && cmnt.pos < next && span_line.line == comment_line.line { self.print_comment(cmnt)?; self.cur_cmnt_and_lit.cur_cmnt += 1; } diff --git a/src/libsyntax/std_inject.rs b/src/libsyntax/std_inject.rs index d1454ab06c..1b63a2b707 100644 --- a/src/libsyntax/std_inject.rs +++ b/src/libsyntax/std_inject.rs @@ -34,23 +34,25 @@ fn ignored_span(sess: &ParseSess, sp: Span) -> Span { return sp; } -pub fn no_core(krate: &ast::Crate) -> bool { - attr::contains_name(&krate.attrs, "no_core") -} - -pub fn no_std(krate: &ast::Crate) -> bool { - attr::contains_name(&krate.attrs, "no_std") || no_core(krate) +pub fn injected_crate_name(krate: &ast::Crate) -> Option<&'static str> { + if attr::contains_name(&krate.attrs, "no_core") { + None + } else if attr::contains_name(&krate.attrs, "no_std") { + Some("core") + } else { + Some("std") + } } pub fn maybe_inject_crates_ref(sess: &ParseSess, mut krate: ast::Crate, alt_std_name: Option) -> ast::Crate { - if no_core(&krate) { - return krate; - } + let name = match injected_crate_name(&krate) { + Some(name) => name, + None => return krate, + }; - let name = if no_std(&krate) { "core" } else { "std" }; let crate_name = token::intern(&alt_std_name.unwrap_or(name.to_string())); krate.module.items.insert(0, P(ast::Item { diff --git a/src/libsyntax/test.rs b/src/libsyntax/test.rs index 6327e8f71b..618878c1f7 100644 --- a/src/libsyntax/test.rs +++ b/src/libsyntax/test.rs @@ -19,7 +19,7 @@ use std::iter; use std::slice; use std::mem; use std::vec; -use attr; +use attr::{self, HasAttrs}; use syntax_pos::{self, DUMMY_SP, NO_EXPANSION, Span, FileMap, BytePos}; use std::rc::Rc; @@ -119,7 +119,7 @@ impl<'a> fold::Folder for TestHarnessGenerator<'a> { } debug!("current path: {}", path_name_i(&self.cx.path)); - let i = if is_test_fn(&self.cx, &i) || is_bench_fn(&self.cx, &i) { + if is_test_fn(&self.cx, &i) || is_bench_fn(&self.cx, &i) { match i.node { ast::ItemKind::Fn(_, ast::Unsafety::Unsafe, _, _, _, _) => { let diag = self.cx.span_diagnostic; @@ -136,54 +136,37 @@ impl<'a> fold::Folder for TestHarnessGenerator<'a> { }; self.cx.testfns.push(test); self.tests.push(i.ident); - // debug!("have {} test/bench functions", - // cx.testfns.len()); - - // Make all tests public so we can call them from outside - // the module (note that the tests are re-exported and must - // be made public themselves to avoid privacy errors). - i.map(|mut i| { - i.vis = ast::Visibility::Public; - i - }) } } - } else { - i - }; + } + let mut item = i.unwrap(); // We don't want to recurse into anything other than mods, since // mods or tests inside of functions will break things - let res = match i.node { - ast::ItemKind::Mod(..) => fold::noop_fold_item(i, self), - _ => SmallVector::one(i), - }; + if let ast::ItemKind::Mod(module) = item.node { + let tests = mem::replace(&mut self.tests, Vec::new()); + let tested_submods = mem::replace(&mut self.tested_submods, Vec::new()); + let mut mod_folded = fold::noop_fold_mod(module, self); + let tests = mem::replace(&mut self.tests, tests); + let tested_submods = mem::replace(&mut self.tested_submods, tested_submods); + + if !tests.is_empty() || !tested_submods.is_empty() { + let (it, sym) = mk_reexport_mod(&mut self.cx, item.id, tests, tested_submods); + mod_folded.items.push(it); + + if !self.cx.path.is_empty() { + self.tested_submods.push((self.cx.path[self.cx.path.len()-1], sym)); + } else { + debug!("pushing nothing, sym: {:?}", sym); + self.cx.toplevel_reexport = Some(sym); + } + } + item.node = ast::ItemKind::Mod(mod_folded); + } if ident.name != keywords::Invalid.name() { self.cx.path.pop(); } - res - } - - fn fold_mod(&mut self, m: ast::Mod) -> ast::Mod { - let tests = mem::replace(&mut self.tests, Vec::new()); - let tested_submods = mem::replace(&mut self.tested_submods, Vec::new()); - let mut mod_folded = fold::noop_fold_mod(m, self); - let tests = mem::replace(&mut self.tests, tests); - let tested_submods = mem::replace(&mut self.tested_submods, tested_submods); - - if !tests.is_empty() || !tested_submods.is_empty() { - let (it, sym) = mk_reexport_mod(&mut self.cx, tests, tested_submods); - mod_folded.items.push(it); - - if !self.cx.path.is_empty() { - self.tested_submods.push((self.cx.path[self.cx.path.len()-1], sym)); - } else { - debug!("pushing nothing, sym: {:?}", sym); - self.cx.toplevel_reexport = Some(sym); - } - } - - mod_folded + SmallVector::one(P(item)) } fn fold_mac(&mut self, mac: ast::Mac) -> ast::Mac { mac } @@ -239,16 +222,24 @@ impl fold::Folder for EntryPointCleaner { fn fold_mac(&mut self, mac: ast::Mac) -> ast::Mac { mac } } -fn mk_reexport_mod(cx: &mut TestCtxt, tests: Vec, +fn mk_reexport_mod(cx: &mut TestCtxt, parent: ast::NodeId, tests: Vec, tested_submods: Vec<(ast::Ident, ast::Ident)>) -> (P, ast::Ident) { let super_ = token::str_to_ident("super"); + // Generate imports with `#[allow(private_in_public)]` to work around issue #36768. + let allow_private_in_public = cx.ext_cx.attribute(DUMMY_SP, cx.ext_cx.meta_list( + DUMMY_SP, + InternedString::new("allow"), + vec![cx.ext_cx.meta_list_item_word(DUMMY_SP, InternedString::new("private_in_public"))], + )); let items = tests.into_iter().map(|r| { cx.ext_cx.item_use_simple(DUMMY_SP, ast::Visibility::Public, cx.ext_cx.path(DUMMY_SP, vec![super_, r])) + .map_attrs(|_| vec![allow_private_in_public.clone()]) }).chain(tested_submods.into_iter().map(|(r, sym)| { let path = cx.ext_cx.path(DUMMY_SP, vec![super_, r, sym]); cx.ext_cx.item_use_simple_(DUMMY_SP, ast::Visibility::Public, r, path) + .map_attrs(|_| vec![allow_private_in_public.clone()]) })).collect(); let reexport_mod = ast::Mod { @@ -257,6 +248,8 @@ fn mk_reexport_mod(cx: &mut TestCtxt, tests: Vec, }; let sym = token::gensym_ident("__test_reexports"); + let parent = if parent == ast::DUMMY_NODE_ID { ast::CRATE_NODE_ID } else { parent }; + cx.ext_cx.current_expansion.mark = cx.ext_cx.resolver.get_module_scope(parent); let it = cx.ext_cx.monotonic_expander().fold_item(P(ast::Item { ident: sym.clone(), attrs: Vec::new(), @@ -281,7 +274,7 @@ fn generate_test_harness(sess: &ParseSess, let mut cx: TestCtxt = TestCtxt { sess: sess, span_diagnostic: sd, - ext_cx: ExtCtxt::new(sess, vec![], ExpansionConfig::default("test".to_string()), resolver), + ext_cx: ExtCtxt::new(sess, ExpansionConfig::default("test".to_string()), resolver), path: Vec::new(), testfns: Vec::new(), reexport_test_harness_main: reexport_test_harness_main, @@ -437,7 +430,7 @@ fn mk_std(cx: &TestCtxt) -> P { let (vi, vis, ident) = if cx.is_test_crate { (ast::ItemKind::Use( P(nospan(ast::ViewPathSimple(id_test, - path_node(vec!(id_test)))))), + path_node(vec![id_test]))))), ast::Visibility::Public, keywords::Invalid.ident()) } else { (ast::ItemKind::ExternCrate(None), ast::Visibility::Inherited, id_test) @@ -579,7 +572,7 @@ fn mk_tests(cx: &TestCtxt) -> P { let static_lt = ecx.lifetime(sp, keywords::StaticLifetime.name()); // &'static [self::test::TestDescAndFn] let static_type = ecx.ty_rptr(sp, - ecx.ty(sp, ast::TyKind::Vec(struct_type)), + ecx.ty(sp, ast::TyKind::Slice(struct_type)), Some(static_lt), ast::Mutability::Immutable); // static TESTS: $static_type = &[...]; diff --git a/src/libsyntax/tokenstream.rs b/src/libsyntax/tokenstream.rs index b35b4617ea..9ef6c07e48 100644 --- a/src/libsyntax/tokenstream.rs +++ b/src/libsyntax/tokenstream.rs @@ -134,9 +134,10 @@ impl TokenTree { AttrStyle::Inner => 3, } } - TokenTree::Token(_, token::SpecialVarNt(..)) => 2, + TokenTree::Token(_, token::Interpolated(ref nt)) => { + if let Nonterminal::NtTT(..) = **nt { 1 } else { 0 } + }, TokenTree::Token(_, token::MatchNt(..)) => 3, - TokenTree::Token(_, token::Interpolated(Nonterminal::NtTT(..))) => 1, TokenTree::Delimited(_, ref delimed) => delimed.tts.len() + 2, TokenTree::Sequence(_, ref seq) => seq.tts.len(), TokenTree::Token(..) => 0, @@ -188,20 +189,12 @@ impl TokenTree { } delimed.tts[index - 1].clone() } - (&TokenTree::Token(sp, token::SpecialVarNt(var)), _) => { - let v = [TokenTree::Token(sp, token::Dollar), - TokenTree::Token(sp, token::Ident(token::str_to_ident(var.as_str())))]; - v[index].clone() - } (&TokenTree::Token(sp, token::MatchNt(name, kind)), _) => { let v = [TokenTree::Token(sp, token::SubstNt(name)), TokenTree::Token(sp, token::Colon), TokenTree::Token(sp, token::Ident(kind))]; v[index].clone() } - (&TokenTree::Token(_, token::Interpolated(Nonterminal::NtTT(ref tt))), _) => { - tt.clone().unwrap() - } (&TokenTree::Sequence(_, ref seq), _) => seq.tts[index].clone(), _ => panic!("Cannot expand a token tree"), } @@ -221,13 +214,10 @@ impl TokenTree { mtch: &[TokenTree], tts: &[TokenTree]) -> macro_parser::NamedParseResult { + let diag = &cx.parse_sess().span_diagnostic; // `None` is because we're not interpolating - let arg_rdr = lexer::new_tt_reader_with_doc_flag(&cx.parse_sess().span_diagnostic, - None, - None, - tts.iter().cloned().collect(), - true); - macro_parser::parse(cx.parse_sess(), cx.cfg(), arg_rdr, mtch) + let arg_rdr = lexer::new_tt_reader(diag, None, tts.iter().cloned().collect()); + macro_parser::parse(cx.parse_sess(), arg_rdr, mtch) } /// Check if this TokenTree is equal to the other, regardless of span information. diff --git a/src/libsyntax/util/interner.rs b/src/libsyntax/util/interner.rs index 6bb409715a..f56c6cedcd 100644 --- a/src/libsyntax/util/interner.rs +++ b/src/libsyntax/util/interner.rs @@ -14,23 +14,13 @@ use ast::Name; -use std::borrow::Borrow; use std::collections::HashMap; use std::rc::Rc; -#[derive(PartialEq, Eq, Hash)] -struct RcStr(Rc); - -impl Borrow for RcStr { - fn borrow(&self) -> &str { - &self.0 - } -} - #[derive(Default)] pub struct Interner { - names: HashMap, - strings: Vec>, + names: HashMap, Name>, + strings: Vec>, } /// When traits can extend traits, we should extend index to get [] @@ -47,22 +37,22 @@ impl Interner { this } - pub fn intern + Into>(&mut self, string: T) -> Name { - if let Some(&name) = self.names.get(string.borrow()) { + pub fn intern(&mut self, string: &str) -> Name { + if let Some(&name) = self.names.get(string) { return name; } let name = Name(self.strings.len() as u32); - let string = Rc::new(string.into()); + let string = Rc::__from_str(string); self.strings.push(string.clone()); - self.names.insert(RcStr(string), name); + self.names.insert(string, name); name } pub fn gensym(&mut self, string: &str) -> Name { let gensym = Name(self.strings.len() as u32); // leave out of `names` to avoid colliding - self.strings.push(Rc::new(string.to_owned())); + self.strings.push(Rc::__from_str(string)); gensym } @@ -75,7 +65,7 @@ impl Interner { gensym } - pub fn get(&self, name: Name) -> Rc { + pub fn get(&self, name: Name) -> Rc { self.strings[name.0 as usize].clone() } @@ -109,13 +99,13 @@ mod tests { assert_eq!(i.gensym("dog"), Name(4)); // gensym tests again with gensym_copy: assert_eq!(i.gensym_copy(Name(2)), Name(5)); - assert_eq!(*i.get(Name(5)), "zebra"); + assert_eq!(&*i.get(Name(5)), "zebra"); assert_eq!(i.gensym_copy(Name(2)), Name(6)); - assert_eq!(*i.get(Name(6)), "zebra"); - assert_eq!(*i.get(Name(0)), "dog"); - assert_eq!(*i.get(Name(1)), "cat"); - assert_eq!(*i.get(Name(2)), "zebra"); - assert_eq!(*i.get(Name(3)), "zebra"); - assert_eq!(*i.get(Name(4)), "dog"); + assert_eq!(&*i.get(Name(6)), "zebra"); + assert_eq!(&*i.get(Name(0)), "dog"); + assert_eq!(&*i.get(Name(1)), "cat"); + assert_eq!(&*i.get(Name(2)), "zebra"); + assert_eq!(&*i.get(Name(3)), "zebra"); + assert_eq!(&*i.get(Name(4)), "dog"); } } diff --git a/src/libsyntax/util/parser_testing.rs b/src/libsyntax/util/parser_testing.rs index f59428bf53..76d3f2a063 100644 --- a/src/libsyntax/util/parser_testing.rs +++ b/src/libsyntax/util/parser_testing.rs @@ -25,10 +25,7 @@ pub fn string_to_tts(source_str: String) -> Vec { /// Map string to parser (via tts) pub fn string_to_parser<'a>(ps: &'a ParseSess, source_str: String) -> Parser<'a> { - new_parser_from_source_str(ps, - Vec::new(), - "bogofile".to_string(), - source_str) + new_parser_from_source_str(ps, "bogofile".to_string(), source_str) } fn with_error_checking_parse<'a, T, F>(s: String, ps: &'a ParseSess, f: F) -> T where diff --git a/src/libsyntax/util/small_vector.rs b/src/libsyntax/util/small_vector.rs index 373dfc4ddf..9be7dbd681 100644 --- a/src/libsyntax/util/small_vector.rs +++ b/src/libsyntax/util/small_vector.rs @@ -11,6 +11,7 @@ use self::SmallVectorRepr::*; use self::IntoIterRepr::*; +use core::ops; use std::iter::{IntoIterator, FromIterator}; use std::mem; use std::slice; @@ -19,10 +20,12 @@ use std::vec; use util::move_map::MoveMap; /// A vector type optimized for cases where the size is almost always 0 or 1 +#[derive(Clone)] pub struct SmallVector { repr: SmallVectorRepr, } +#[derive(Clone)] enum SmallVectorRepr { Zero, One(T), @@ -75,16 +78,11 @@ impl SmallVector { } pub fn as_slice(&self) -> &[T] { - match self.repr { - Zero => { - let result: &[T] = &[]; - result - } - One(ref v) => { - unsafe { slice::from_raw_parts(v, 1) } - } - Many(ref vs) => vs - } + self + } + + pub fn as_mut_slice(&mut self) -> &mut [T] { + self } pub fn pop(&mut self) -> Option { @@ -107,7 +105,7 @@ impl SmallVector { One(..) => { let one = mem::replace(&mut self.repr, Zero); match one { - One(v1) => mem::replace(&mut self.repr, Many(vec!(v1, v))), + One(v1) => mem::replace(&mut self.repr, Many(vec![v1, v])), _ => unreachable!() }; } @@ -163,6 +161,38 @@ impl SmallVector { } } +impl ops::Deref for SmallVector { + type Target = [T]; + + fn deref(&self) -> &[T] { + match self.repr { + Zero => { + let result: &[T] = &[]; + result + } + One(ref v) => { + unsafe { slice::from_raw_parts(v, 1) } + } + Many(ref vs) => vs + } + } +} + +impl ops::DerefMut for SmallVector { + fn deref_mut(&mut self) -> &mut [T] { + match self.repr { + Zero => { + let result: &mut [T] = &mut []; + result + } + One(ref mut v) => { + unsafe { slice::from_raw_parts_mut(v, 1) } + } + Many(ref mut vs) => vs + } + } +} + impl IntoIterator for SmallVector { type Item = T; type IntoIter = IntoIter; @@ -284,12 +314,12 @@ mod tests { #[test] #[should_panic] fn test_expect_one_many() { - SmallVector::many(vec!(1, 2)).expect_one(""); + SmallVector::many(vec![1, 2]).expect_one(""); } #[test] fn test_expect_one_one() { assert_eq!(1, SmallVector::one(1).expect_one("")); - assert_eq!(1, SmallVector::many(vec!(1)).expect_one("")); + assert_eq!(1, SmallVector::many(vec![1]).expect_one("")); } } diff --git a/src/libsyntax/visit.rs b/src/libsyntax/visit.rs index 57b06c4087..7fb3e5c6be 100644 --- a/src/libsyntax/visit.rs +++ b/src/libsyntax/visit.rs @@ -201,6 +201,7 @@ pub fn walk_lifetime(visitor: &mut V, lifetime: &Lifetime) { pub fn walk_lifetime_def(visitor: &mut V, lifetime_def: &LifetimeDef) { visitor.visit_lifetime(&lifetime_def.lifetime); walk_list!(visitor, visit_lifetime, &lifetime_def.bounds); + walk_list!(visitor, visit_attribute, &*lifetime_def.attrs); } pub fn walk_poly_trait_ref(visitor: &mut V, trait_ref: &PolyTraitRef, _: &TraitBoundModifier) @@ -313,7 +314,7 @@ pub fn walk_variant(visitor: &mut V, variant: &Variant, generics: &Generics, pub fn walk_ty(visitor: &mut V, typ: &Ty) { match typ.node { - TyKind::Vec(ref ty) | TyKind::Paren(ref ty) => { + TyKind::Slice(ref ty) | TyKind::Paren(ref ty) => { visitor.visit_ty(ty) } TyKind::Ptr(ref mutable_type) => { @@ -341,7 +342,7 @@ pub fn walk_ty(visitor: &mut V, typ: &Ty) { visitor.visit_ty(ty); walk_list!(visitor, visit_ty_param_bound, bounds); } - TyKind::FixedLengthVec(ref ty, ref expression) => { + TyKind::Array(ref ty, ref expression) => { visitor.visit_ty(ty); visitor.visit_expr(expression) } @@ -434,7 +435,7 @@ pub fn walk_pat(visitor: &mut V, pattern: &Pat) { visitor.visit_expr(upper_bound) } PatKind::Wild => (), - PatKind::Vec(ref prepatterns, ref slice_pattern, ref postpatterns) => { + PatKind::Slice(ref prepatterns, ref slice_pattern, ref postpatterns) => { walk_list!(visitor, visit_pat, prepatterns); walk_list!(visitor, visit_pat, slice_pattern); walk_list!(visitor, visit_pat, postpatterns); @@ -474,6 +475,7 @@ pub fn walk_generics(visitor: &mut V, generics: &Generics) { visitor.visit_ident(param.span, param.ident); walk_list!(visitor, visit_ty_param_bound, ¶m.bounds); walk_list!(visitor, visit_ty, ¶m.default); + walk_list!(visitor, visit_attribute, &*param.attrs); } walk_list!(visitor, visit_lifetime_def, &generics.lifetimes); for predicate in &generics.where_clause.predicates { diff --git a/src/libsyntax_ext/Cargo.toml b/src/libsyntax_ext/Cargo.toml index 6910e6400d..960db792a6 100644 --- a/src/libsyntax_ext/Cargo.toml +++ b/src/libsyntax_ext/Cargo.toml @@ -11,7 +11,7 @@ crate-type = ["dylib"] [dependencies] fmt_macros = { path = "../libfmt_macros" } log = { path = "../liblog" } +proc_macro = { path = "../libproc_macro" } rustc_errors = { path = "../librustc_errors" } -rustc_macro = { path = "../librustc_macro" } syntax = { path = "../libsyntax" } syntax_pos = { path = "../libsyntax_pos" } diff --git a/src/libsyntax_ext/asm.rs b/src/libsyntax_ext/asm.rs index cc4fb604d6..e4d0cb7404 100644 --- a/src/libsyntax_ext/asm.rs +++ b/src/libsyntax_ext/asm.rs @@ -107,7 +107,7 @@ pub fn expand_asm<'cx>(cx: &'cx mut ExtCtxt, if p2.token != token::Eof { let mut extra_tts = panictry!(p2.parse_all_token_trees()); extra_tts.extend(tts[first_colon..].iter().cloned()); - p = parse::tts_to_parser(cx.parse_sess, extra_tts, cx.cfg()); + p = parse::tts_to_parser(cx.parse_sess, extra_tts); } asm = s; @@ -122,7 +122,7 @@ pub fn expand_asm<'cx>(cx: &'cx mut ExtCtxt, let (constraint, _str_style) = panictry!(p.parse_str()); - let span = p.last_span; + let span = p.prev_span; panictry!(p.expect(&token::OpenDelim(token::Paren))); let out = panictry!(p.parse_expr()); @@ -167,9 +167,9 @@ pub fn expand_asm<'cx>(cx: &'cx mut ExtCtxt, let (constraint, _str_style) = panictry!(p.parse_str()); if constraint.starts_with("=") { - cx.span_err(p.last_span, "input operand constraint contains '='"); + cx.span_err(p.prev_span, "input operand constraint contains '='"); } else if constraint.starts_with("+") { - cx.span_err(p.last_span, "input operand constraint contains '+'"); + cx.span_err(p.prev_span, "input operand constraint contains '+'"); } panictry!(p.expect(&token::OpenDelim(token::Paren))); @@ -189,9 +189,9 @@ pub fn expand_asm<'cx>(cx: &'cx mut ExtCtxt, 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"); + cx.span_warn(p.prev_span, "expected a clobber, found an option"); } else if s.starts_with("{") || s.ends_with("}") { - cx.span_err(p.last_span, "clobber should not be surrounded by braces"); + cx.span_err(p.prev_span, "clobber should not be surrounded by braces"); } clobs.push(s); @@ -209,7 +209,7 @@ pub fn expand_asm<'cx>(cx: &'cx mut ExtCtxt, } else if option == "intel" { dialect = AsmDialect::Intel; } else { - cx.span_warn(p.last_span, "unrecognized option"); + cx.span_warn(p.prev_span, "unrecognized option"); } if p.token == token::Comma { @@ -250,7 +250,7 @@ pub fn expand_asm<'cx>(cx: &'cx mut ExtCtxt, MacEager::expr(P(ast::Expr { id: ast::DUMMY_NODE_ID, - node: ast::ExprKind::InlineAsm(ast::InlineAsm { + node: ast::ExprKind::InlineAsm(P(ast::InlineAsm { asm: token::intern_and_get_ident(&asm), asm_str_style: asm_str_style.unwrap(), outputs: outputs, @@ -260,7 +260,7 @@ pub fn expand_asm<'cx>(cx: &'cx mut ExtCtxt, alignstack: alignstack, dialect: dialect, expn_id: expn_id, - }), + })), span: sp, attrs: ast::ThinVec::new(), })) diff --git a/src/libsyntax_ext/cfg.rs b/src/libsyntax_ext/cfg.rs index 169ef9ab7d..98da49545f 100644 --- a/src/libsyntax_ext/cfg.rs +++ b/src/libsyntax_ext/cfg.rs @@ -32,6 +32,6 @@ pub fn expand_cfg<'cx>(cx: &mut ExtCtxt, return DummyResult::expr(sp); } - let matches_cfg = attr::cfg_matches(&cx.cfg, &cfg, cx.parse_sess, cx.ecfg.features); + let matches_cfg = attr::cfg_matches(&cfg, cx.parse_sess, cx.ecfg.features); MacEager::expr(cx.expr_bool(sp, matches_cfg)) } diff --git a/src/libsyntax_ext/deriving/cmp/partial_eq.rs b/src/libsyntax_ext/deriving/cmp/partial_eq.rs index 64b8829dad..c46d4b3417 100644 --- a/src/libsyntax_ext/deriving/cmp/partial_eq.rs +++ b/src/libsyntax_ext/deriving/cmp/partial_eq.rs @@ -65,12 +65,12 @@ pub fn expand_deriving_partial_eq(cx: &mut ExtCtxt, macro_rules! md { ($name:expr, $f:ident) => { { let inline = cx.meta_word(span, InternedString::new("inline")); - let attrs = vec!(cx.attribute(span, inline)); + let attrs = vec![cx.attribute(span, inline)]; MethodDef { name: $name, generics: LifetimeBounds::empty(), explicit_self: borrowed_explicit_self(), - args: vec!(borrowed_self()), + args: vec![borrowed_self()], ret_ty: Literal(path_local!(bool)), attributes: attrs, is_unsafe: false, diff --git a/src/libsyntax_ext/deriving/cmp/partial_ord.rs b/src/libsyntax_ext/deriving/cmp/partial_ord.rs index 99d60c43c5..597ff306b3 100644 --- a/src/libsyntax_ext/deriving/cmp/partial_ord.rs +++ b/src/libsyntax_ext/deriving/cmp/partial_ord.rs @@ -28,12 +28,12 @@ pub fn expand_deriving_partial_ord(cx: &mut ExtCtxt, macro_rules! md { ($name:expr, $op:expr, $equal:expr) => { { let inline = cx.meta_word(span, InternedString::new("inline")); - let attrs = vec!(cx.attribute(span, inline)); + let attrs = vec![cx.attribute(span, inline)]; MethodDef { name: $name, generics: LifetimeBounds::empty(), explicit_self: borrowed_explicit_self(), - args: vec!(borrowed_self()), + args: vec![borrowed_self()], ret_ty: Literal(path_local!(bool)), attributes: attrs, is_unsafe: false, diff --git a/src/libsyntax_ext/deriving/custom.rs b/src/libsyntax_ext/deriving/custom.rs index 624fabd142..f8cb1294a6 100644 --- a/src/libsyntax_ext/deriving/custom.rs +++ b/src/libsyntax_ext/deriving/custom.rs @@ -11,7 +11,7 @@ use std::panic; use errors::FatalError; -use rustc_macro::{TokenStream, __internal}; +use proc_macro::{TokenStream, __internal}; use syntax::ast::{self, ItemKind}; use syntax::codemap::{ExpnInfo, MacroAttribute, NameAndSpan, Span}; use syntax::ext::base::*; diff --git a/src/libsyntax_ext/deriving/decodable.rs b/src/libsyntax_ext/deriving/decodable.rs index 22b9eb8e75..10db56d46f 100644 --- a/src/libsyntax_ext/deriving/decodable.rs +++ b/src/libsyntax_ext/deriving/decodable.rs @@ -79,9 +79,9 @@ fn expand_deriving_decodable_imp(cx: &mut ExtCtxt, ret_ty: Literal(Path::new_(pathvec_std!(cx, core::result::Result), None, - vec!(Box::new(Self_), Box::new(Literal(Path::new_( + vec![Box::new(Self_), Box::new(Literal(Path::new_( vec![typaram, "Error"], None, vec![], false - )))), + )))], true)), attributes: Vec::new(), is_unsafe: false, diff --git a/src/libsyntax_ext/deriving/encodable.rs b/src/libsyntax_ext/deriving/encodable.rs index a4074184b6..640296d7f0 100644 --- a/src/libsyntax_ext/deriving/encodable.rs +++ b/src/libsyntax_ext/deriving/encodable.rs @@ -139,23 +139,23 @@ fn expand_deriving_encodable_imp(cx: &mut ExtCtxt, generics: LifetimeBounds::empty(), is_unsafe: false, supports_unions: false, - methods: vec!( + methods: vec![ MethodDef { name: "encode", generics: LifetimeBounds { lifetimes: Vec::new(), bounds: vec![(typaram, - vec![Path::new_(vec![krate, "Encoder"], None, vec!(), true)])] + vec![Path::new_(vec![krate, "Encoder"], None, vec![], true)])] }, explicit_self: borrowed_explicit_self(), - args: vec!(Ptr(Box::new(Literal(Path::new_local(typaram))), - Borrowed(None, Mutability::Mutable))), + args: vec![Ptr(Box::new(Literal(Path::new_local(typaram))), + Borrowed(None, Mutability::Mutable))], ret_ty: Literal(Path::new_( pathvec_std!(cx, core::result::Result), None, - vec!(Box::new(Tuple(Vec::new())), Box::new(Literal(Path::new_( + vec![Box::new(Tuple(Vec::new())), Box::new(Literal(Path::new_( vec![typaram, "Error"], None, vec![], false - )))), + )))], true )), attributes: Vec::new(), @@ -165,7 +165,7 @@ fn expand_deriving_encodable_imp(cx: &mut ExtCtxt, encodable_substructure(a, b, c, krate) })), } - ), + ], associated_types: Vec::new(), }; diff --git a/src/libsyntax_ext/deriving/generic/mod.rs b/src/libsyntax_ext/deriving/generic/mod.rs index e307925a6e..e6b63be3ef 100644 --- a/src/libsyntax_ext/deriving/generic/mod.rs +++ b/src/libsyntax_ext/deriving/generic/mod.rs @@ -536,7 +536,7 @@ impl<'a> TraitDef<'a> { bounds.push((*declared_bound).clone()); } - cx.typaram(self.span, ty_param.ident, P::from_vec(bounds), None) + cx.typaram(self.span, ty_param.ident, vec![], P::from_vec(bounds), None) })); // and similarly for where clauses @@ -1460,8 +1460,9 @@ impl<'a> MethodDef<'a> { .iter() .map(|v| { let ident = v.node.name; + let sp = Span { expn_id: trait_.span.expn_id, ..v.span }; let summary = trait_.summarise_struct(cx, &v.node.data); - (ident, v.span, summary) + (ident, sp, summary) }) .collect(); self.call_substructure_method(cx, @@ -1545,7 +1546,7 @@ impl<'a> TraitDef<'a> { cx.span_bug(sp, "a braced struct with unnamed fields in `derive`"); } codemap::Spanned { - span: pat.span, + span: Span { expn_id: self.span.expn_id, ..pat.span }, node: ast::FieldPat { ident: ident.unwrap(), pat: pat, @@ -1576,7 +1577,8 @@ impl<'a> TraitDef<'a> { mutbl: ast::Mutability) -> (P, Vec<(Span, Option, P, &'a [ast::Attribute])>) { let variant_ident = variant.node.name; - let variant_path = cx.path(variant.span, vec![enum_ident, variant_ident]); + let sp = Span { expn_id: self.span.expn_id, ..variant.span }; + let variant_path = cx.path(sp, vec![enum_ident, variant_ident]); self.create_struct_pattern(cx, variant_path, &variant.node.data, prefix, mutbl) } } diff --git a/src/libsyntax_ext/deriving/generic/ty.rs b/src/libsyntax_ext/deriving/generic/ty.rs index 210878b7c9..4749d082bc 100644 --- a/src/libsyntax_ext/deriving/generic/ty.rs +++ b/src/libsyntax_ext/deriving/generic/ty.rs @@ -194,6 +194,7 @@ impl<'a> Ty<'a> { fn mk_ty_param(cx: &ExtCtxt, span: Span, name: &str, + attrs: &[ast::Attribute], bounds: &[Path], self_ident: Ident, self_generics: &Generics) @@ -204,7 +205,7 @@ fn mk_ty_param(cx: &ExtCtxt, cx.typarambound(path) }) .collect(); - cx.typaram(span, cx.ident_of(name), bounds, None) + cx.typaram(span, cx.ident_of(name), attrs.to_owned(), bounds, None) } fn mk_generics(lifetimes: Vec, ty_params: Vec, span: Span) @@ -246,7 +247,7 @@ impl<'a> LifetimeBounds<'a> { let bounds = bounds.iter() .map(|b| cx.lifetime(span, cx.ident_of(*b).name)) .collect(); - cx.lifetime_def(span, cx.ident_of(*lt).name, bounds) + cx.lifetime_def(span, cx.ident_of(*lt).name, vec![], bounds) }) .collect(); let ty_params = self.bounds @@ -254,7 +255,7 @@ impl<'a> LifetimeBounds<'a> { .map(|t| { match *t { (ref name, ref bounds) => { - mk_ty_param(cx, span, *name, bounds, self_ty, self_generics) + mk_ty_param(cx, span, *name, &[], bounds, self_ty, self_generics) } } }) diff --git a/src/libsyntax_ext/deriving/mod.rs b/src/libsyntax_ext/deriving/mod.rs index e3a38d568d..c2bfead568 100644 --- a/src/libsyntax_ext/deriving/mod.rs +++ b/src/libsyntax_ext/deriving/mod.rs @@ -11,7 +11,8 @@ //! The compiler code necessary to implement the `#[derive]` extensions. use syntax::ast::{self, MetaItem}; -use syntax::ext::base::{Annotatable, ExtCtxt}; +use syntax::attr::HasAttrs; +use syntax::ext::base::{Annotatable, ExtCtxt, SyntaxExtension}; use syntax::ext::build::AstBuilder; use syntax::feature_gate; use syntax::codemap; @@ -27,7 +28,7 @@ macro_rules! pathvec { macro_rules! path { ($($x:tt)*) => ( - ::ext::deriving::generic::ty::Path::new( pathvec!( $($x)* ) ) + ::ext::deriving::generic::ty::Path::new( pathvec![ $($x)* ] ) ) } @@ -39,7 +40,7 @@ macro_rules! path_local { macro_rules! pathvec_std { ($cx:expr, $first:ident :: $($rest:ident)::+) => ({ - let mut v = pathvec!($($rest)::+); + let mut v = pathvec![$($rest)::+]; if let Some(s) = $cx.crate_root { v.insert(0, s); } @@ -104,15 +105,150 @@ pub fn expand_derive(cx: &mut ExtCtxt, } }; - if mitem.value_str().is_some() { - cx.span_err(mitem.span, "unexpected value in `derive`"); + let mut derive_attrs = Vec::new(); + item = item.map_attrs(|attrs| { + let partition = attrs.into_iter().partition(|attr| &attr.name() == "derive"); + derive_attrs = partition.0; + partition.1 + }); + + // Expand `#[derive]`s after other attribute macro invocations. + if cx.resolver.find_attr_invoc(&mut item.attrs.clone()).is_some() { + return vec![Annotatable::Item(item.map_attrs(|mut attrs| { + attrs.push(cx.attribute(span, P(mitem.clone()))); + attrs.extend(derive_attrs); + attrs + }))]; + } + + let get_traits = |mitem: &MetaItem, cx: &ExtCtxt| { + if mitem.value_str().is_some() { + cx.span_err(mitem.span, "unexpected value in `derive`"); + } + + let traits = mitem.meta_item_list().unwrap_or(&[]).to_owned(); + if traits.is_empty() { + cx.span_warn(mitem.span, "empty trait list in `derive`"); + } + traits + }; + + let mut traits = get_traits(mitem, cx); + for derive_attr in derive_attrs { + traits.extend(get_traits(&derive_attr.node.value, cx)); + } + + // First, weed out malformed #[derive] + traits.retain(|titem| { + if titem.word().is_none() { + cx.span_err(titem.span, "malformed `derive` entry"); + false + } else { + true + } + }); + + // Next, check for old-style #[derive(Foo)] + // + // These all get expanded to `#[derive_Foo]` and will get expanded first. If + // we actually add any attributes here then we return to get those expanded + // and then eventually we'll come back to finish off the other derive modes. + let mut new_attributes = Vec::new(); + traits.retain(|titem| { + let tword = titem.word().unwrap(); + let tname = tword.name(); + + if is_builtin_trait(&tname) || { + let derive_mode = + ast::Path::from_ident(titem.span, ast::Ident::with_empty_ctxt(intern(&tname))); + cx.resolver.resolve_macro(cx.current_expansion.mark, &derive_mode, false).map(|ext| { + if let SyntaxExtension::CustomDerive(_) = *ext { true } else { false } + }).unwrap_or(false) + } { + return true; + } + + if !cx.ecfg.enable_custom_derive() { + feature_gate::emit_feature_err(&cx.parse_sess, + "custom_derive", + titem.span, + feature_gate::GateIssue::Language, + feature_gate::EXPLAIN_CUSTOM_DERIVE); + } else { + cx.span_warn(titem.span, feature_gate::EXPLAIN_DEPR_CUSTOM_DERIVE); + let name = intern_and_get_ident(&format!("derive_{}", tname)); + let mitem = cx.meta_word(titem.span, name); + new_attributes.push(cx.attribute(mitem.span, mitem)); + } + false + }); + if new_attributes.len() > 0 { + item = item.map(|mut i| { + i.attrs.extend(new_attributes); + if traits.len() > 0 { + let list = cx.meta_list(mitem.span, + intern_and_get_ident("derive"), + traits); + i.attrs.push(cx.attribute(mitem.span, list)); + } + i + }); + return vec![Annotatable::Item(item)] } - let traits = mitem.meta_item_list().unwrap_or(&[]); - if traits.is_empty() { - cx.span_warn(mitem.span, "empty trait list in `derive`"); + // Now check for macros-1.1 style custom #[derive]. + // + // Expand each of them in order given, but *before* we expand any built-in + // derive modes. The logic here is to: + // + // 1. Collect the remaining `#[derive]` annotations into a list. If + // there are any left, attach a `#[derive]` attribute to the item + // that we're currently expanding with the remaining derive modes. + // 2. Manufacture a `#[derive(Foo)]` attribute to pass to the expander. + // 3. Expand the current item we're expanding, getting back a list of + // items that replace it. + // 4. Extend the returned list with the current list of items we've + // collected so far. + // 5. Return everything! + // + // If custom derive extensions end up threading through the `#[derive]` + // attribute, we'll get called again later on to continue expanding + // those modes. + let macros_11_derive = traits.iter() + .cloned() + .enumerate() + .filter(|&(_, ref name)| !is_builtin_trait(&name.name().unwrap())) + .next(); + if let Some((i, titem)) = macros_11_derive { + let tname = ast::Ident::with_empty_ctxt(intern(&titem.name().unwrap())); + let path = ast::Path::from_ident(titem.span, tname); + let ext = cx.resolver.resolve_macro(cx.current_expansion.mark, &path, false).unwrap(); + + traits.remove(i); + if traits.len() > 0 { + item = item.map(|mut i| { + let list = cx.meta_list(mitem.span, + intern_and_get_ident("derive"), + traits); + i.attrs.push(cx.attribute(mitem.span, list)); + i + }); + } + let titem = cx.meta_list_item_word(titem.span, titem.name().unwrap()); + let mitem = cx.meta_list(titem.span, + intern_and_get_ident("derive"), + vec![titem]); + let item = Annotatable::Item(item); + if let SyntaxExtension::CustomDerive(ref ext) = *ext { + return ext.expand(cx, mitem.span, &mitem, item); + } else { + unreachable!() + } } + // Ok, at this point we know that there are no old-style `#[derive_Foo]` nor + // any macros-1.1 style `#[derive(Foo)]`. Expand all built-in traits here. + // RFC #1445. `#[derive(PartialEq, Eq)]` adds a (trusted) // `#[structural_match]` attribute. if traits.iter().filter_map(|t| t.name()).any(|t| t == "PartialEq") && @@ -141,103 +277,33 @@ pub fn expand_derive(cx: &mut ExtCtxt, }); } - let mut other_items = Vec::new(); - - let mut iter = traits.iter(); - while let Some(titem) = iter.next() { - - let tword = match titem.word() { - Some(name) => name, - None => { - cx.span_err(titem.span, "malformed `derive` entry"); - continue - } + let mut items = Vec::new(); + for titem in traits.iter() { + let tname = titem.word().unwrap().name(); + let name = intern_and_get_ident(&format!("derive({})", tname)); + let mitem = cx.meta_word(titem.span, name); + + let span = Span { + expn_id: cx.codemap().record_expansion(codemap::ExpnInfo { + call_site: titem.span, + callee: codemap::NameAndSpan { + format: codemap::MacroAttribute(intern(&format!("derive({})", tname))), + span: Some(titem.span), + allow_internal_unstable: true, + }, + }), + ..titem.span }; - let tname = tword.name(); - - // If this is a built-in derive mode, then we expand it immediately - // here. - if is_builtin_trait(&tname) { - let name = intern_and_get_ident(&format!("derive({})", tname)); - let mitem = cx.meta_word(titem.span, name); - let span = Span { - expn_id: cx.codemap().record_expansion(codemap::ExpnInfo { - call_site: titem.span, - callee: codemap::NameAndSpan { - format: codemap::MacroAttribute(intern(&format!("derive({})", tname))), - span: Some(titem.span), - allow_internal_unstable: true, - }, - }), - ..titem.span - }; - - let my_item = Annotatable::Item(item); - expand_builtin(&tname, cx, span, &mitem, &my_item, &mut |a| { - other_items.push(a); - }); - item = my_item.expect_item(); - - // Otherwise if this is a `rustc_macro`-style derive mode, we process it - // here. The logic here is to: - // - // 1. Collect the remaining `#[derive]` annotations into a list. If - // there are any left, attach a `#[derive]` attribute to the item - // that we're currently expanding with the remaining derive modes. - // 2. Manufacture a `#[derive(Foo)]` attribute to pass to the expander. - // 3. Expand the current item we're expanding, getting back a list of - // items that replace it. - // 4. Extend the returned list with the current list of items we've - // collected so far. - // 5. Return everything! - // - // If custom derive extensions end up threading through the `#[derive]` - // attribute, we'll get called again later on to continue expanding - // those modes. - } else if let Some(ext) = - cx.resolver.resolve_derive_mode(ast::Ident::with_empty_ctxt(intern(&tname))) { - let remaining_derives = iter.cloned().collect::>(); - if remaining_derives.len() > 0 { - let list = cx.meta_list(titem.span, - intern_and_get_ident("derive"), - remaining_derives); - let attr = cx.attribute(titem.span, list); - item = item.map(|mut i| { - i.attrs.push(attr); - i - }); - } - let titem = cx.meta_list_item_word(titem.span, tname.clone()); - let mitem = cx.meta_list(titem.span, - intern_and_get_ident("derive"), - vec![titem]); - let item = Annotatable::Item(item); - let mut items = ext.expand(cx, mitem.span, &mitem, item); - items.extend(other_items); - return items - - // If we've gotten this far then it means that we're in the territory of - // the old custom derive mechanism. If the feature isn't enabled, we - // issue an error, otherwise manufacture the `derive_Foo` attribute. - } else if !cx.ecfg.enable_custom_derive() { - feature_gate::emit_feature_err(&cx.parse_sess, - "custom_derive", - titem.span, - feature_gate::GateIssue::Language, - feature_gate::EXPLAIN_CUSTOM_DERIVE); - } else { - let name = intern_and_get_ident(&format!("derive_{}", tname)); - let mitem = cx.meta_word(titem.span, name); - item = item.map(|mut i| { - i.attrs.push(cx.attribute(mitem.span, mitem)); - i - }); - } + let my_item = Annotatable::Item(item); + expand_builtin(&tname, cx, span, &mitem, &my_item, &mut |a| { + items.push(a); + }); + item = my_item.expect_item(); } - other_items.insert(0, Annotatable::Item(item)); - return other_items + items.insert(0, Annotatable::Item(item)); + return items } macro_rules! derive_traits { diff --git a/src/libsyntax_ext/format.rs b/src/libsyntax_ext/format.rs index 892ebcfa76..de78f859f0 100644 --- a/src/libsyntax_ext/format.rs +++ b/src/libsyntax_ext/format.rs @@ -506,7 +506,7 @@ impl<'a, 'b> Context<'a, 'b> { -> P { let sp = piece_ty.span; let ty = ecx.ty_rptr(sp, - ecx.ty(sp, ast::TyKind::Vec(piece_ty)), + ecx.ty(sp, ast::TyKind::Slice(piece_ty)), Some(ecx.lifetime(sp, keywords::StaticLifetime.name())), ast::Mutability::Immutable); let slice = ecx.expr_vec_slice(sp, pieces); diff --git a/src/libsyntax_ext/lib.rs b/src/libsyntax_ext/lib.rs index bd9f1cf0d7..e1542c9e46 100644 --- a/src/libsyntax_ext/lib.rs +++ b/src/libsyntax_ext/lib.rs @@ -19,9 +19,9 @@ html_root_url = "https://doc.rust-lang.org/nightly/")] #![cfg_attr(not(stage0), deny(warnings))] -#![feature(dotdot_in_tuple_patterns)] -#![feature(rustc_macro_lib)] -#![feature(rustc_macro_internals)] +#![cfg_attr(stage0, feature(dotdot_in_tuple_patterns))] +#![feature(proc_macro_lib)] +#![feature(proc_macro_internals)] #![feature(rustc_private)] #![feature(staged_api)] @@ -31,7 +31,7 @@ extern crate log; #[macro_use] extern crate syntax; extern crate syntax_pos; -extern crate rustc_macro; +extern crate proc_macro; extern crate rustc_errors as errors; mod asm; @@ -43,28 +43,30 @@ mod format; mod log_syntax; mod trace_macros; -pub mod rustc_macro_registrar; +pub mod proc_macro_registrar; // for custom_derive pub mod deriving; use std::rc::Rc; use syntax::ast; -use syntax::ext::base::{MacroExpanderFn, NormalTT, IdentTT, MultiModifier}; -use syntax::ext::hygiene::Mark; +use syntax::ext::base::{MacroExpanderFn, NormalTT, IdentTT, MultiModifier, NamedSyntaxExtension}; use syntax::ext::tt::macro_rules::MacroRulesExpander; use syntax::parse::token::intern; -pub fn register_builtins(resolver: &mut syntax::ext::base::Resolver, enable_quotes: bool) { +pub fn register_builtins(resolver: &mut syntax::ext::base::Resolver, + user_exts: Vec, + enable_quotes: bool) { let mut register = |name, ext| { - resolver.add_ext(Mark::root(), ast::Ident::with_empty_ctxt(intern(name)), Rc::new(ext)); + resolver.add_ext(ast::Ident::with_empty_ctxt(name), Rc::new(ext)); }; - register("macro_rules", IdentTT(Box::new(MacroRulesExpander), None, false)); + register(intern("macro_rules"), IdentTT(Box::new(MacroRulesExpander), None, false)); macro_rules! register { ($( $name:ident: $f:expr, )*) => { $( - register(stringify!($name), NormalTT(Box::new($f as MacroExpanderFn), None, false)); + register(intern(stringify!($name)), + NormalTT(Box::new($f as MacroExpanderFn), None, false)); )* } } @@ -109,7 +111,11 @@ pub fn register_builtins(resolver: &mut syntax::ext::base::Resolver, enable_quot } // format_args uses `unstable` things internally. - register("format_args", NormalTT(Box::new(format::expand_format_args), None, true)); + register(intern("format_args"), NormalTT(Box::new(format::expand_format_args), None, true)); - register("derive", MultiModifier(Box::new(deriving::expand_derive))); + register(intern("derive"), MultiModifier(Box::new(deriving::expand_derive))); + + for (name, ext) in user_exts { + register(name, ext); + } } diff --git a/src/libsyntax_ext/rustc_macro_registrar.rs b/src/libsyntax_ext/proc_macro_registrar.rs similarity index 77% rename from src/libsyntax_ext/rustc_macro_registrar.rs rename to src/libsyntax_ext/proc_macro_registrar.rs index ce3e53cdf9..a8accd63dc 100644 --- a/src/libsyntax_ext/rustc_macro_registrar.rs +++ b/src/libsyntax_ext/proc_macro_registrar.rs @@ -36,45 +36,45 @@ struct CollectCustomDerives<'a> { derives: Vec, in_root: bool, handler: &'a errors::Handler, - is_rustc_macro_crate: bool, + is_proc_macro_crate: bool, } pub fn modify(sess: &ParseSess, resolver: &mut ::syntax::ext::base::Resolver, mut krate: ast::Crate, - is_rustc_macro_crate: bool, + is_proc_macro_crate: bool, num_crate_types: usize, handler: &errors::Handler, features: &Features) -> ast::Crate { - let ecfg = ExpansionConfig::default("rustc_macro".to_string()); - let mut cx = ExtCtxt::new(sess, Vec::new(), ecfg, resolver); + let ecfg = ExpansionConfig::default("proc_macro".to_string()); + let mut cx = ExtCtxt::new(sess, ecfg, resolver); let mut collect = CollectCustomDerives { derives: Vec::new(), in_root: true, handler: handler, - is_rustc_macro_crate: is_rustc_macro_crate, + is_proc_macro_crate: is_proc_macro_crate, }; visit::walk_crate(&mut collect, &krate); - if !is_rustc_macro_crate { + if !is_proc_macro_crate { return krate - } else if !features.rustc_macro { - let mut err = handler.struct_err("the `rustc-macro` crate type is \ + } else if !features.proc_macro { + let mut err = handler.struct_err("the `proc-macro` crate type is \ experimental"); - err.help("add #![feature(rustc_macro)] to the crate attributes to \ + err.help("add #![feature(proc_macro)] to the crate attributes to \ enable"); err.emit(); } if num_crate_types > 1 { - handler.err("cannot mix `rustc-macro` crate type with others"); + handler.err("cannot mix `proc-macro` crate type with others"); } krate.module.items.push(mk_registrar(&mut cx, &collect.derives)); if krate.exported_macros.len() > 0 { - handler.err("cannot export macro_rules! macros from a `rustc-macro` \ + handler.err("cannot export macro_rules! macros from a `proc-macro` \ crate type currently"); } @@ -83,13 +83,13 @@ pub fn modify(sess: &ParseSess, impl<'a> CollectCustomDerives<'a> { fn check_not_pub_in_root(&self, vis: &ast::Visibility, sp: Span) { - if self.is_rustc_macro_crate && + if self.is_proc_macro_crate && self.in_root && *vis == ast::Visibility::Public { self.handler.span_err(sp, - "`rustc-macro` crate types cannot \ + "`proc-macro` crate types cannot \ export any items other than functions \ - tagged with `#[rustc_macro_derive]` \ + tagged with `#[proc_macro_derive]` \ currently"); } } @@ -100,18 +100,29 @@ impl<'a> Visitor for CollectCustomDerives<'a> { // First up, make sure we're checking a bare function. If we're not then // we're just not interested in this item. // - // If we find one, try to locate a `#[rustc_macro_derive]` attribute on + // If we find one, try to locate a `#[proc_macro_derive]` attribute on // it. match item.node { ast::ItemKind::Fn(..) => {} _ => { + // Check for invalid use of proc_macro_derive + let attr = item.attrs.iter() + .filter(|a| a.check_name("proc_macro_derive")) + .next(); + if let Some(attr) = attr { + self.handler.span_err(attr.span(), + "the `#[proc_macro_derive]` \ + attribute may only be used \ + on bare functions"); + return; + } self.check_not_pub_in_root(&item.vis, item.span); return visit::walk_item(self, item) } } let mut attrs = item.attrs.iter() - .filter(|a| a.check_name("rustc_macro_derive")); + .filter(|a| a.check_name("proc_macro_derive")); let attr = match attrs.next() { Some(attr) => attr, None => { @@ -121,25 +132,25 @@ impl<'a> Visitor for CollectCustomDerives<'a> { }; if let Some(a) = attrs.next() { - self.handler.span_err(a.span(), "multiple `#[rustc_macro_derive]` \ + self.handler.span_err(a.span(), "multiple `#[proc_macro_derive]` \ attributes found"); } - if !self.is_rustc_macro_crate { + if !self.is_proc_macro_crate { self.handler.span_err(attr.span(), - "the `#[rustc_macro_derive]` attribute is \ - only usable with crates of the `rustc-macro` \ + "the `#[proc_macro_derive]` attribute is \ + only usable with crates of the `proc-macro` \ crate type"); } - // Once we've located the `#[rustc_macro_derive]` attribute, verify - // that it's of the form `#[rustc_macro_derive(Foo)]` + // Once we've located the `#[proc_macro_derive]` attribute, verify + // that it's of the form `#[proc_macro_derive(Foo)]` let list = match attr.meta_item_list() { Some(list) => list, None => { self.handler.span_err(attr.span(), "attribute must be of form: \ - #[rustc_macro_derive(TraitName)]"); + #[proc_macro_derive(TraitName)]"); return } }; @@ -177,7 +188,7 @@ impl<'a> Visitor for CollectCustomDerives<'a> { function_name: item.ident, }); } else { - let msg = "functions tagged with `#[rustc_macro_derive]` must \ + let msg = "functions tagged with `#[proc_macro_derive]` must \ currently reside in the root of the crate"; self.handler.span_err(item.span, msg); } @@ -202,9 +213,9 @@ impl<'a> Visitor for CollectCustomDerives<'a> { // Creates a new module which looks like: // // mod $gensym { -// extern crate rustc_macro; +// extern crate proc_macro; // -// use rustc_macro::__internal::Registry; +// use proc_macro::__internal::Registry; // // #[plugin_registrar] // fn registrar(registrar: &mut Registry) { @@ -218,16 +229,16 @@ fn mk_registrar(cx: &mut ExtCtxt, let eid = cx.codemap().record_expansion(ExpnInfo { call_site: DUMMY_SP, callee: NameAndSpan { - format: MacroAttribute(token::intern("rustc_macro")), + format: MacroAttribute(token::intern("proc_macro")), span: None, allow_internal_unstable: true, } }); let span = Span { expn_id: eid, ..DUMMY_SP }; - let rustc_macro = token::str_to_ident("rustc_macro"); + let proc_macro = token::str_to_ident("proc_macro"); let krate = cx.item(span, - rustc_macro, + proc_macro, Vec::new(), ast::ItemKind::ExternCrate(None)); @@ -241,7 +252,7 @@ fn mk_registrar(cx: &mut ExtCtxt, (path, trait_name) }).map(|(path, trait_name)| { let registrar = cx.expr_ident(span, registrar); - let ufcs_path = cx.path(span, vec![rustc_macro, __internal, registry, + let ufcs_path = cx.path(span, vec![proc_macro, __internal, registry, register_custom_derive]); cx.expr_call(span, cx.expr_path(ufcs_path), @@ -250,7 +261,7 @@ fn mk_registrar(cx: &mut ExtCtxt, cx.stmt_expr(expr) }).collect::>(); - let path = cx.path(span, vec![rustc_macro, __internal, registry]); + let path = cx.path(span, vec![proc_macro, __internal, registry]); let registrar_path = cx.ty_path(path); let arg_ty = cx.ty_rptr(span, registrar_path, None, ast::Mutability::Mutable); let func = cx.item_fn(span, diff --git a/src/libsyntax_pos/lib.rs b/src/libsyntax_pos/lib.rs index d83d3a6c5c..d99850332c 100644 --- a/src/libsyntax_pos/lib.rs +++ b/src/libsyntax_pos/lib.rs @@ -67,7 +67,7 @@ pub struct Span { /// the error, and would be rendered with `^^^`. /// - they can have a *label*. In this case, the label is written next /// to the mark in the snippet when we render. -#[derive(Clone)] +#[derive(Clone, Debug, PartialEq, Eq)] pub struct MultiSpan { primary_spans: Vec, span_labels: Vec<(Span, String)>, diff --git a/src/libtest/lib.rs b/src/libtest/lib.rs index 9407e29834..95ae6eb2ef 100644 --- a/src/libtest/lib.rs +++ b/src/libtest/lib.rs @@ -34,8 +34,6 @@ #![cfg_attr(not(stage0), deny(warnings))] #![feature(asm)] -#![feature(box_syntax)] -#![feature(fnbox)] #![feature(libc)] #![feature(rustc_private)] #![feature(set_stdio)] @@ -56,8 +54,7 @@ use self::TestEvent::*; use self::NamePadding::*; use self::OutputLocation::*; -use std::boxed::FnBox; - +use std::panic::{catch_unwind, AssertUnwindSafe}; use std::any::Any; use std::cmp; use std::collections::BTreeMap; @@ -135,6 +132,16 @@ pub trait TDynBenchFn: Send { fn run(&self, harness: &mut Bencher); } +pub trait FnBox: Send + 'static { + fn call_box(self: Box, t: T); +} + +impl FnBox for F { + fn call_box(self: Box, t: T) { + (*self)(t) + } +} + // A function that runs a test. If the function returns successfully, // the test succeeds; if the function panics then the test fails. We // may need to come up with a more clever definition of test in order @@ -143,8 +150,8 @@ pub enum TestFn { StaticTestFn(fn()), StaticBenchFn(fn(&mut Bencher)), StaticMetricFn(fn(&mut MetricMap)), - DynTestFn(Box), - DynMetricFn(Box), + DynTestFn(Box>), + DynMetricFn(Box FnBox<&'a mut MetricMap>>), DynBenchFn(Box), } @@ -303,6 +310,7 @@ pub struct TestOpts { pub color: ColorConfig, pub quiet: bool, pub test_threads: Option, + pub skip: Vec, } impl TestOpts { @@ -318,6 +326,7 @@ impl TestOpts { color: AutoColor, quiet: false, test_threads: None, + skip: vec![], } } } @@ -327,7 +336,7 @@ pub type OptRes = Result; #[cfg_attr(rustfmt, rustfmt_skip)] fn optgroups() -> Vec { - vec!(getopts::optflag("", "ignored", "Run ignored tests"), + vec![getopts::optflag("", "ignored", "Run ignored tests"), getopts::optflag("", "test", "Run tests and not benchmarks"), getopts::optflag("", "bench", "Run benchmarks instead of tests"), getopts::optflag("h", "help", "Display this message (longer with --help)"), @@ -337,11 +346,13 @@ fn optgroups() -> Vec { task, allow printing directly"), getopts::optopt("", "test-threads", "Number of threads used for running tests \ in parallel", "n_threads"), + getopts::optmulti("", "skip", "Skip tests whose names contain FILTER (this flag can \ + be used multiple times)","FILTER"), getopts::optflag("q", "quiet", "Display one character per test instead of one line"), getopts::optopt("", "color", "Configure coloring of output: auto = colorize if stdout is a tty and tests are run on serially (default); always = always colorize output; - never = never colorize output;", "auto|always|never")) + never = never colorize output;", "auto|always|never")] } fn usage(binary: &str) { @@ -446,6 +457,7 @@ pub fn parse_opts(args: &[String]) -> Option { color: color, quiet: quiet, test_threads: test_threads, + skip: matches.opt_strs("skip"), }; Some(Ok(test_opts)) @@ -1024,7 +1036,8 @@ fn get_concurrency() -> usize { target_os = "ios", target_os = "android", target_os = "solaris", - target_os = "emscripten"))] + target_os = "emscripten", + target_os = "fuchsia"))] fn num_cpus() -> usize { unsafe { libc::sysconf(libc::_SC_NPROCESSORS_ONLN) as usize } } @@ -1101,6 +1114,11 @@ pub fn filter_tests(opts: &TestOpts, tests: Vec) -> Vec) -> Vec) -> Vec { // convert benchmarks to tests, if we're not benchmarking them - tests.into_iter() - .map(|x| { - let testfn = match x.testfn { - DynBenchFn(bench) => { - DynTestFn(Box::new(move || bench::run_once(|b| bench.run(b)))) - } - StaticBenchFn(benchfn) => { - DynTestFn(Box::new(move || bench::run_once(|b| benchfn(b)))) - } - f => f, - }; - TestDescAndFn { - desc: x.desc, - testfn: testfn, - } - }) - .collect() + tests.into_iter().map(|x| { + let testfn = match x.testfn { + DynBenchFn(bench) => { + DynTestFn(Box::new(move |()| { + bench::run_once(|b| bench.run(b)) + })) + } + StaticBenchFn(benchfn) => { + DynTestFn(Box::new(move |()| { + bench::run_once(|b| benchfn(b)) + })) + } + f => f, + }; + TestDescAndFn { + desc: x.desc, + testfn: testfn, + } + }).collect() } pub fn run_test(opts: &TestOpts, @@ -1161,7 +1181,7 @@ pub fn run_test(opts: &TestOpts, fn run_test_inner(desc: TestDesc, monitor_ch: Sender, nocapture: bool, - testfn: Box) { + testfn: Box>) { struct Sink(Arc>>); impl Write for Sink { fn write(&mut self, data: &[u8]) -> io::Result { @@ -1172,26 +1192,49 @@ pub fn run_test(opts: &TestOpts, } } - thread::spawn(move || { - let data = Arc::new(Mutex::new(Vec::new())); - let data2 = data.clone(); - let cfg = thread::Builder::new().name(match desc.name { - DynTestName(ref name) => name.clone(), - StaticTestName(name) => name.to_owned(), - }); + // Buffer for capturing standard I/O + let data = Arc::new(Mutex::new(Vec::new())); + let data2 = data.clone(); + + let name = desc.name.clone(); + let runtest = move || { + let oldio = if !nocapture { + Some(( + io::set_print(Some(Box::new(Sink(data2.clone())))), + io::set_panic(Some(Box::new(Sink(data2)))) + )) + } else { + None + }; - let result_guard = cfg.spawn(move || { - if !nocapture { - io::set_print(box Sink(data2.clone())); - io::set_panic(box Sink(data2)); - } - testfn() - }) - .unwrap(); - let test_result = calc_result(&desc, result_guard.join()); + let result = catch_unwind(AssertUnwindSafe(|| { + testfn.call_box(()) + })); + + if let Some((printio, panicio)) = oldio { + io::set_print(printio); + io::set_panic(panicio); + }; + + let test_result = calc_result(&desc, result); let stdout = data.lock().unwrap().to_vec(); monitor_ch.send((desc.clone(), test_result, stdout)).unwrap(); - }); + }; + + + // If the platform is single-threaded we're just going to run + // the test synchronously, regardless of the concurrency + // level. + let supports_threads = !cfg!(target_os = "emscripten"); + if supports_threads { + let cfg = thread::Builder::new().name(match name { + DynTestName(ref name) => name.clone(), + StaticTestName(name) => name.to_owned(), + }); + cfg.spawn(runtest).unwrap(); + } else { + runtest(); + } } match testfn { @@ -1207,7 +1250,7 @@ pub fn run_test(opts: &TestOpts, } DynMetricFn(f) => { let mut mm = MetricMap::new(); - f.call_box((&mut mm,)); + f.call_box(&mut mm); monitor_ch.send((desc, TrMetrics(mm), Vec::new())).unwrap(); return; } @@ -1218,7 +1261,8 @@ pub fn run_test(opts: &TestOpts, return; } DynTestFn(f) => run_test_inner(desc, monitor_ch, opts.nocapture, f), - StaticTestFn(f) => run_test_inner(desc, monitor_ch, opts.nocapture, Box::new(f)), + StaticTestFn(f) => run_test_inner(desc, monitor_ch, opts.nocapture, + Box::new(move |()| f())), } } @@ -1281,7 +1325,7 @@ impl MetricMap { /// /// This function is a no-op, and does not even read from `dummy`. #[cfg(not(any(all(target_os = "nacl", target_arch = "le32"), - target_arch = "asmjs")))] + target_arch = "asmjs", target_arch = "wasm32")))] pub fn black_box(dummy: T) -> T { // we need to "use" the argument in some way LLVM can't // introspect. @@ -1289,7 +1333,7 @@ pub fn black_box(dummy: T) -> T { dummy } #[cfg(any(all(target_os = "nacl", target_arch = "le32"), - target_arch = "asmjs"))] + target_arch = "asmjs", target_arch = "wasm32"))] #[inline(never)] pub fn black_box(dummy: T) -> T { dummy @@ -1453,7 +1497,7 @@ mod tests { ignore: true, should_panic: ShouldPanic::No, }, - testfn: DynTestFn(Box::new(move || f())), + testfn: DynTestFn(Box::new(move |()| f())), }; let (tx, rx) = channel(); run_test(&TestOpts::new(), false, desc, tx); @@ -1470,7 +1514,7 @@ mod tests { ignore: true, should_panic: ShouldPanic::No, }, - testfn: DynTestFn(Box::new(move || f())), + testfn: DynTestFn(Box::new(move |()| f())), }; let (tx, rx) = channel(); run_test(&TestOpts::new(), false, desc, tx); @@ -1489,7 +1533,7 @@ mod tests { ignore: false, should_panic: ShouldPanic::Yes, }, - testfn: DynTestFn(Box::new(move || f())), + testfn: DynTestFn(Box::new(move |()| f())), }; let (tx, rx) = channel(); run_test(&TestOpts::new(), false, desc, tx); @@ -1508,7 +1552,7 @@ mod tests { ignore: false, should_panic: ShouldPanic::YesWithMessage("error message"), }, - testfn: DynTestFn(Box::new(move || f())), + testfn: DynTestFn(Box::new(move |()| f())), }; let (tx, rx) = channel(); run_test(&TestOpts::new(), false, desc, tx); @@ -1527,7 +1571,7 @@ mod tests { ignore: false, should_panic: ShouldPanic::YesWithMessage("foobar"), }, - testfn: DynTestFn(Box::new(move || f())), + testfn: DynTestFn(Box::new(move |()| f())), }; let (tx, rx) = channel(); run_test(&TestOpts::new(), false, desc, tx); @@ -1544,7 +1588,7 @@ mod tests { ignore: false, should_panic: ShouldPanic::Yes, }, - testfn: DynTestFn(Box::new(move || f())), + testfn: DynTestFn(Box::new(move |()| f())), }; let (tx, rx) = channel(); run_test(&TestOpts::new(), false, desc, tx); @@ -1577,7 +1621,7 @@ mod tests { ignore: true, should_panic: ShouldPanic::No, }, - testfn: DynTestFn(Box::new(move || {})), + testfn: DynTestFn(Box::new(move |()| {})), }, TestDescAndFn { desc: TestDesc { @@ -1585,7 +1629,7 @@ mod tests { ignore: false, should_panic: ShouldPanic::No, }, - testfn: DynTestFn(Box::new(move || {})), + testfn: DynTestFn(Box::new(move |()| {})), }]; let filtered = filter_tests(&opts, tests); @@ -1618,7 +1662,7 @@ mod tests { ignore: false, should_panic: ShouldPanic::No, }, - testfn: DynTestFn(Box::new(testfn)), + testfn: DynTestFn(Box::new(move |()| testfn())), }; tests.push(test); } diff --git a/src/libunwind/build.rs b/src/libunwind/build.rs index e1ddf8b4b7..db41a368a1 100644 --- a/src/libunwind/build.rs +++ b/src/libunwind/build.rs @@ -35,5 +35,7 @@ fn main() { println!("cargo:rustc-link-lib=gcc_pic"); } else if target.contains("windows-gnu") { println!("cargo:rustc-link-lib=gcc_eh"); + } else if target.contains("fuchsia") { + println!("cargo:rustc-link-lib=unwind"); } } diff --git a/src/libunwind/libunwind.rs b/src/libunwind/libunwind.rs index 30de859f15..bbac6c07c5 100644 --- a/src/libunwind/libunwind.rs +++ b/src/libunwind/libunwind.rs @@ -65,7 +65,7 @@ pub const unwinder_private_data_size: usize = 2; #[cfg(target_arch = "s390x")] pub const unwinder_private_data_size: usize = 2; -#[cfg(target_arch = "asmjs")] +#[cfg(target_os = "emscripten")] pub const unwinder_private_data_size: usize = 20; #[repr(C)] @@ -252,6 +252,8 @@ if #[cfg(not(all(target_os = "ios", target_arch = "arm")))] { any(target_arch = "x86", target_arch = "x86_64"), not(test)), link(name = "unwind", kind = "static"))] +#[cfg_attr(target_os = "fuchsia", + link(name = "unwind"))] #[cfg_attr(any(target_os = "android", target_os = "openbsd"), link(name = "gcc"))] #[cfg_attr(all(target_os = "netbsd", not(target_vendor = "rumprun")), diff --git a/src/rtstartup/rsbegin.rs b/src/rtstartup/rsbegin.rs index b57b7e8432..65c85697ce 100644 --- a/src/rtstartup/rsbegin.rs +++ b/src/rtstartup/rsbegin.rs @@ -44,7 +44,7 @@ pub mod eh_frames { // Scratch space for unwinder's internal book-keeping. // This is defined as `struct object` in $GCC/libgcc/unwind-dw2-fde.h. - static mut obj: [isize; 6] = [0; 6]; + static mut OBJ: [isize; 6] = [0; 6]; // Unwind info registration/deregistration routines. // See the docs of `unwind` module in libstd. @@ -56,13 +56,13 @@ pub mod eh_frames { unsafe fn init() { // register unwind info on module startup rust_eh_register_frames(&__EH_FRAME_BEGIN__ as *const u8, - &mut obj as *mut _ as *mut u8); + &mut OBJ as *mut _ as *mut u8); } unsafe fn uninit() { // unregister on shutdown rust_eh_unregister_frames(&__EH_FRAME_BEGIN__ as *const u8, - &mut obj as *mut _ as *mut u8); + &mut OBJ as *mut _ as *mut u8); } // MSVC-specific init/uninit routine registration diff --git a/src/rustc/Cargo.lock b/src/rustc/Cargo.lock deleted file mode 100644 index 69e3eab22e..0000000000 --- a/src/rustc/Cargo.lock +++ /dev/null @@ -1,413 +0,0 @@ -[root] -name = "rustc-main" -version = "0.0.0" -dependencies = [ - "rustc_back 0.0.0", - "rustc_driver 0.0.0", - "rustdoc 0.0.0", -] - -[[package]] -name = "arena" -version = "0.0.0" - -[[package]] -name = "build_helper" -version = "0.1.0" - -[[package]] -name = "flate" -version = "0.0.0" -dependencies = [ - "build_helper 0.1.0", - "gcc 0.3.28 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "fmt_macros" -version = "0.0.0" - -[[package]] -name = "gcc" -version = "0.3.28" -source = "registry+https://github.com/rust-lang/crates.io-index" - -[[package]] -name = "graphviz" -version = "0.0.0" - -[[package]] -name = "log" -version = "0.0.0" - -[[package]] -name = "proc_macro" -version = "0.0.0" -dependencies = [ - "log 0.0.0", - "rustc_plugin 0.0.0", - "syntax 0.0.0", - "syntax_pos 0.0.0", -] - -[[package]] -name = "rustc" -version = "0.0.0" -dependencies = [ - "arena 0.0.0", - "flate 0.0.0", - "fmt_macros 0.0.0", - "graphviz 0.0.0", - "log 0.0.0", - "rustc_back 0.0.0", - "rustc_bitflags 0.0.0", - "rustc_const_math 0.0.0", - "rustc_data_structures 0.0.0", - "rustc_errors 0.0.0", - "rustc_llvm 0.0.0", - "serialize 0.0.0", - "syntax 0.0.0", - "syntax_pos 0.0.0", -] - -[[package]] -name = "rustc_back" -version = "0.0.0" -dependencies = [ - "log 0.0.0", - "serialize 0.0.0", - "syntax 0.0.0", -] - -[[package]] -name = "rustc_bitflags" -version = "0.0.0" - -[[package]] -name = "rustc_borrowck" -version = "0.0.0" -dependencies = [ - "graphviz 0.0.0", - "log 0.0.0", - "rustc 0.0.0", - "rustc_data_structures 0.0.0", - "rustc_errors 0.0.0", - "rustc_mir 0.0.0", - "syntax 0.0.0", - "syntax_pos 0.0.0", -] - -[[package]] -name = "rustc_const_eval" -version = "0.0.0" -dependencies = [ - "graphviz 0.0.0", - "log 0.0.0", - "rustc 0.0.0", - "rustc_back 0.0.0", - "rustc_const_math 0.0.0", - "rustc_errors 0.0.0", - "serialize 0.0.0", - "syntax 0.0.0", - "syntax_pos 0.0.0", -] - -[[package]] -name = "rustc_const_math" -version = "0.0.0" -dependencies = [ - "log 0.0.0", - "serialize 0.0.0", - "syntax 0.0.0", -] - -[[package]] -name = "rustc_data_structures" -version = "0.0.0" -dependencies = [ - "log 0.0.0", - "serialize 0.0.0", -] - -[[package]] -name = "rustc_driver" -version = "0.0.0" -dependencies = [ - "arena 0.0.0", - "flate 0.0.0", - "graphviz 0.0.0", - "log 0.0.0", - "proc_macro 0.0.0", - "rustc 0.0.0", - "rustc_back 0.0.0", - "rustc_borrowck 0.0.0", - "rustc_const_eval 0.0.0", - "rustc_errors 0.0.0", - "rustc_incremental 0.0.0", - "rustc_lint 0.0.0", - "rustc_llvm 0.0.0", - "rustc_metadata 0.0.0", - "rustc_mir 0.0.0", - "rustc_passes 0.0.0", - "rustc_plugin 0.0.0", - "rustc_privacy 0.0.0", - "rustc_resolve 0.0.0", - "rustc_save_analysis 0.0.0", - "rustc_trans 0.0.0", - "rustc_typeck 0.0.0", - "serialize 0.0.0", - "syntax 0.0.0", - "syntax_ext 0.0.0", - "syntax_pos 0.0.0", -] - -[[package]] -name = "rustc_errors" -version = "0.0.0" -dependencies = [ - "log 0.0.0", - "serialize 0.0.0", - "syntax_pos 0.0.0", -] - -[[package]] -name = "rustc_incremental" -version = "0.0.0" -dependencies = [ - "graphviz 0.0.0", - "log 0.0.0", - "rustc 0.0.0", - "rustc_data_structures 0.0.0", - "serialize 0.0.0", - "syntax 0.0.0", - "syntax_pos 0.0.0", -] - -[[package]] -name = "rustc_lint" -version = "0.0.0" -dependencies = [ - "log 0.0.0", - "rustc 0.0.0", - "rustc_back 0.0.0", - "rustc_const_eval 0.0.0", - "syntax 0.0.0", - "syntax_pos 0.0.0", -] - -[[package]] -name = "rustc_llvm" -version = "0.0.0" -dependencies = [ - "build_helper 0.1.0", - "gcc 0.3.28 (registry+https://github.com/rust-lang/crates.io-index)", - "rustc_bitflags 0.0.0", -] - -[[package]] -name = "rustc_macro" -version = "0.0.0" -dependencies = [ - "syntax 0.0.0", -] - -[[package]] -name = "rustc_metadata" -version = "0.0.0" -dependencies = [ - "flate 0.0.0", - "log 0.0.0", - "rustc 0.0.0", - "rustc_back 0.0.0", - "rustc_const_math 0.0.0", - "rustc_data_structures 0.0.0", - "rustc_errors 0.0.0", - "rustc_llvm 0.0.0", - "rustc_macro 0.0.0", - "serialize 0.0.0", - "syntax 0.0.0", - "syntax_ext 0.0.0", - "syntax_pos 0.0.0", -] - -[[package]] -name = "rustc_mir" -version = "0.0.0" -dependencies = [ - "graphviz 0.0.0", - "log 0.0.0", - "rustc 0.0.0", - "rustc_back 0.0.0", - "rustc_bitflags 0.0.0", - "rustc_const_eval 0.0.0", - "rustc_const_math 0.0.0", - "rustc_data_structures 0.0.0", - "syntax 0.0.0", - "syntax_pos 0.0.0", -] - -[[package]] -name = "rustc_passes" -version = "0.0.0" -dependencies = [ - "log 0.0.0", - "rustc 0.0.0", - "rustc_const_eval 0.0.0", - "rustc_const_math 0.0.0", - "rustc_errors 0.0.0", - "syntax 0.0.0", - "syntax_pos 0.0.0", -] - -[[package]] -name = "rustc_platform_intrinsics" -version = "0.0.0" - -[[package]] -name = "rustc_plugin" -version = "0.0.0" -dependencies = [ - "log 0.0.0", - "rustc 0.0.0", - "rustc_back 0.0.0", - "rustc_bitflags 0.0.0", - "rustc_errors 0.0.0", - "rustc_metadata 0.0.0", - "syntax 0.0.0", - "syntax_pos 0.0.0", -] - -[[package]] -name = "rustc_privacy" -version = "0.0.0" -dependencies = [ - "rustc 0.0.0", - "syntax 0.0.0", - "syntax_pos 0.0.0", -] - -[[package]] -name = "rustc_resolve" -version = "0.0.0" -dependencies = [ - "arena 0.0.0", - "log 0.0.0", - "rustc 0.0.0", - "rustc_errors 0.0.0", - "syntax 0.0.0", - "syntax_pos 0.0.0", -] - -[[package]] -name = "rustc_save_analysis" -version = "0.0.0" -dependencies = [ - "log 0.0.0", - "rustc 0.0.0", - "serialize 0.0.0", - "syntax 0.0.0", - "syntax_pos 0.0.0", -] - -[[package]] -name = "rustc_trans" -version = "0.0.0" -dependencies = [ - "arena 0.0.0", - "flate 0.0.0", - "graphviz 0.0.0", - "log 0.0.0", - "rustc 0.0.0", - "rustc_back 0.0.0", - "rustc_const_eval 0.0.0", - "rustc_const_math 0.0.0", - "rustc_data_structures 0.0.0", - "rustc_errors 0.0.0", - "rustc_incremental 0.0.0", - "rustc_llvm 0.0.0", - "rustc_platform_intrinsics 0.0.0", - "serialize 0.0.0", - "syntax 0.0.0", - "syntax_pos 0.0.0", -] - -[[package]] -name = "rustc_typeck" -version = "0.0.0" -dependencies = [ - "arena 0.0.0", - "fmt_macros 0.0.0", - "log 0.0.0", - "rustc 0.0.0", - "rustc_back 0.0.0", - "rustc_const_eval 0.0.0", - "rustc_const_math 0.0.0", - "rustc_errors 0.0.0", - "rustc_platform_intrinsics 0.0.0", - "syntax 0.0.0", - "syntax_pos 0.0.0", -] - -[[package]] -name = "rustdoc" -version = "0.0.0" -dependencies = [ - "arena 0.0.0", - "build_helper 0.1.0", - "gcc 0.3.28 (registry+https://github.com/rust-lang/crates.io-index)", - "log 0.0.0", - "rustc 0.0.0", - "rustc_back 0.0.0", - "rustc_const_eval 0.0.0", - "rustc_const_math 0.0.0", - "rustc_data_structures 0.0.0", - "rustc_driver 0.0.0", - "rustc_errors 0.0.0", - "rustc_lint 0.0.0", - "rustc_metadata 0.0.0", - "rustc_resolve 0.0.0", - "rustc_trans 0.0.0", - "serialize 0.0.0", - "syntax 0.0.0", - "syntax_pos 0.0.0", -] - -[[package]] -name = "serialize" -version = "0.0.0" -dependencies = [ - "log 0.0.0", -] - -[[package]] -name = "syntax" -version = "0.0.0" -dependencies = [ - "log 0.0.0", - "rustc_bitflags 0.0.0", - "rustc_errors 0.0.0", - "serialize 0.0.0", - "syntax_pos 0.0.0", -] - -[[package]] -name = "syntax_ext" -version = "0.0.0" -dependencies = [ - "fmt_macros 0.0.0", - "log 0.0.0", - "rustc_errors 0.0.0", - "rustc_macro 0.0.0", - "syntax 0.0.0", - "syntax_pos 0.0.0", -] - -[[package]] -name = "syntax_pos" -version = "0.0.0" -dependencies = [ - "serialize 0.0.0", -] - -[metadata] -"checksum gcc 0.3.28 (registry+https://github.com/rust-lang/crates.io-index)" = "3da3a2cbaeb01363c8e3704fd9fd0eb2ceb17c6f27abd4c1ef040fb57d20dc79" diff --git a/src/rustc/std_shim/Cargo.lock b/src/rustc/std_shim/Cargo.lock deleted file mode 100644 index b460235545..0000000000 --- a/src/rustc/std_shim/Cargo.lock +++ /dev/null @@ -1,132 +0,0 @@ -[root] -name = "std_shim" -version = "0.1.0" -dependencies = [ - "core 0.0.0", - "std 0.0.0", -] - -[[package]] -name = "alloc" -version = "0.0.0" -dependencies = [ - "core 0.0.0", -] - -[[package]] -name = "alloc_jemalloc" -version = "0.0.0" -dependencies = [ - "build_helper 0.1.0", - "core 0.0.0", - "gcc 0.3.27 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.0.0", -] - -[[package]] -name = "alloc_system" -version = "0.0.0" -dependencies = [ - "core 0.0.0", - "libc 0.0.0", -] - -[[package]] -name = "build_helper" -version = "0.1.0" - -[[package]] -name = "collections" -version = "0.0.0" -dependencies = [ - "alloc 0.0.0", - "core 0.0.0", - "rustc_unicode 0.0.0", -] - -[[package]] -name = "compiler_builtins" -version = "0.0.0" -dependencies = [ - "core 0.0.0", - "gcc 0.3.27 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "core" -version = "0.0.0" - -[[package]] -name = "gcc" -version = "0.3.27" -source = "registry+https://github.com/rust-lang/crates.io-index" - -[[package]] -name = "libc" -version = "0.0.0" -dependencies = [ - "core 0.0.0", -] - -[[package]] -name = "panic_abort" -version = "0.0.0" -dependencies = [ - "core 0.0.0", - "libc 0.0.0", -] - -[[package]] -name = "panic_unwind" -version = "0.0.0" -dependencies = [ - "alloc 0.0.0", - "core 0.0.0", - "libc 0.0.0", - "unwind 0.0.0", -] - -[[package]] -name = "rand" -version = "0.0.0" -dependencies = [ - "core 0.0.0", -] - -[[package]] -name = "rustc_unicode" -version = "0.0.0" -dependencies = [ - "core 0.0.0", -] - -[[package]] -name = "std" -version = "0.0.0" -dependencies = [ - "alloc 0.0.0", - "alloc_jemalloc 0.0.0", - "alloc_system 0.0.0", - "build_helper 0.1.0", - "collections 0.0.0", - "compiler_builtins 0.0.0", - "core 0.0.0", - "gcc 0.3.27 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.0.0", - "panic_abort 0.0.0", - "panic_unwind 0.0.0", - "rand 0.0.0", - "rustc_unicode 0.0.0", - "unwind 0.0.0", -] - -[[package]] -name = "unwind" -version = "0.0.0" -dependencies = [ - "core 0.0.0", - "libc 0.0.0", -] - -[metadata] -"checksum gcc 0.3.27 (registry+https://github.com/rust-lang/crates.io-index)" = "806e63121fbf30760b060a5fc2d1e9f47e1bd356d183e8870367c6c12cc9d5ed" diff --git a/src/rustc/test_shim/Cargo.lock b/src/rustc/test_shim/Cargo.lock deleted file mode 100644 index 73df56d359..0000000000 --- a/src/rustc/test_shim/Cargo.lock +++ /dev/null @@ -1,23 +0,0 @@ -[root] -name = "test_shim" -version = "0.1.0" -dependencies = [ - "test 0.0.0", -] - -[[package]] -name = "getopts" -version = "0.0.0" - -[[package]] -name = "term" -version = "0.0.0" - -[[package]] -name = "test" -version = "0.0.0" -dependencies = [ - "getopts 0.0.0", - "term 0.0.0", -] - diff --git a/src/rustllvm/RustWrapper.cpp b/src/rustllvm/RustWrapper.cpp index 672ab117f1..369388caa0 100644 --- a/src/rustllvm/RustWrapper.cpp +++ b/src/rustllvm/RustWrapper.cpp @@ -562,8 +562,6 @@ extern "C" LLVMRustMetadataRef LLVMRustDIBuilderCreateVariable( LLVMRustMetadataRef Ty, bool AlwaysPreserve, unsigned Flags, - int64_t* AddrOps, - unsigned AddrOpsCount, unsigned ArgNo) { #if LLVM_VERSION_GE(3, 8) if (Tag == 0x100) { // DW_TAG_auto_variable @@ -645,23 +643,6 @@ extern "C" LLVMValueRef LLVMRustDIBuilderInsertDeclareAtEnd( unwrap(InsertAtEnd))); } -extern "C" LLVMValueRef LLVMRustDIBuilderInsertDeclareBefore( - LLVMRustDIBuilderRef Builder, - LLVMValueRef Val, - LLVMRustMetadataRef VarInfo, - int64_t* AddrOps, - unsigned AddrOpsCount, - LLVMValueRef DL, - LLVMValueRef InsertBefore) { - return wrap(Builder->insertDeclare( - unwrap(Val), - unwrap(VarInfo), - Builder->createExpression( - llvm::ArrayRef(AddrOps, AddrOpsCount)), - DebugLoc(cast(unwrap(DL)->getMetadata())), - unwrap(InsertBefore))); -} - extern "C" LLVMRustMetadataRef LLVMRustDIBuilderCreateEnumerator( LLVMRustDIBuilderRef Builder, const char* Name, @@ -1302,7 +1283,7 @@ static LLVMLinkage from_rust(LLVMRustLinkage linkage) { return LLVMCommonLinkage; default: llvm_unreachable("Invalid LLVMRustLinkage value!"); - } + } } extern "C" LLVMRustLinkage LLVMRustGetLinkage(LLVMValueRef V) { diff --git a/src/rustllvm/llvm-auto-clean-trigger b/src/rustllvm/llvm-auto-clean-trigger index b12e25bba6..37fded948e 100644 --- a/src/rustllvm/llvm-auto-clean-trigger +++ b/src/rustllvm/llvm-auto-clean-trigger @@ -1,4 +1,4 @@ # If this file is modified, then llvm will be forcibly cleaned and then rebuilt. # The actual contents of this file do not matter, but to trigger a change on the # build bots then the contents should be changed so git updates the mtime. -2016-10-10 +2016-10-29 diff --git a/src/stage0.txt b/src/stage0.txt index bfab0211b3..7535c32146 100644 --- a/src/stage0.txt +++ b/src/stage0.txt @@ -12,5 +12,5 @@ # tarball for a stable release you'll likely see `1.x.0-$date` where `1.x.0` was # released on `$date` -rustc: 1.12.1-2016-10-20 -cargo: nightly-2016-08-21 +rustc: 1.13.0-2016-11-08 +cargo: nightly-2016-11-02 diff --git a/src/test/codegen-units/item-collection/overloaded-operators.rs b/src/test/codegen-units/item-collection/overloaded-operators.rs index c275eb954b..0295311334 100644 --- a/src/test/codegen-units/item-collection/overloaded-operators.rs +++ b/src/test/codegen-units/item-collection/overloaded-operators.rs @@ -45,8 +45,8 @@ impl IndexMut for Indexable { } -//~ TRANS_ITEM fn overloaded_operators::{{impl}}[2]::eq[0] -//~ TRANS_ITEM fn overloaded_operators::{{impl}}[2]::ne[0] +//~ TRANS_ITEM fn overloaded_operators::{{impl}}[4]::eq[0] +//~ TRANS_ITEM fn overloaded_operators::{{impl}}[4]::ne[0] #[derive(PartialEq)] pub struct Equatable(u32); @@ -54,7 +54,7 @@ pub struct Equatable(u32); impl Add for Equatable { type Output = u32; - //~ TRANS_ITEM fn overloaded_operators::{{impl}}[3]::add[0] + //~ TRANS_ITEM fn overloaded_operators::{{impl}}[2]::add[0] fn add(self, rhs: u32) -> u32 { self.0 + rhs } @@ -63,7 +63,7 @@ impl Add for Equatable { impl Deref for Equatable { type Target = u32; - //~ TRANS_ITEM fn overloaded_operators::{{impl}}[4]::deref[0] + //~ TRANS_ITEM fn overloaded_operators::{{impl}}[3]::deref[0] fn deref(&self) -> &Self::Target { &self.0 } diff --git a/src/test/codegen/abi-sysv64.rs b/src/test/codegen/abi-sysv64.rs index 2b8e8a1b6b..4f6a50eab4 100644 --- a/src/test/codegen/abi-sysv64.rs +++ b/src/test/codegen/abi-sysv64.rs @@ -12,6 +12,9 @@ // llvm. Also checks that the abi-sysv64 feature gate allows usage // of the sysv64 abi. +// ignore-arm +// ignore-aarch64 + // compile-flags: -C no-prepopulate-passes #![crate_type = "lib"] diff --git a/src/test/codegen/consts.rs b/src/test/codegen/consts.rs index 36a582ca73..33b4221b73 100644 --- a/src/test/codegen/consts.rs +++ b/src/test/codegen/consts.rs @@ -19,12 +19,12 @@ // CHECK: @STATIC = {{.*}}, align 4 // This checks the constants from inline_enum_const -// CHECK: @ref{{[0-9]+}} = {{.*}}, align 2 +// CHECK: @ref.{{[0-9]+}} = {{.*}}, align 2 // This checks the constants from {low,high}_align_const, they share the same // constant, but the alignment differs, so the higher one should be used -// CHECK: [[LOW_HIGH:@ref[0-9]+]] = {{.*}}, align 4 -// CHECK: [[LOW_HIGH_REF:@const[0-9]+]] = {{.*}} [[LOW_HIGH]] +// CHECK: [[LOW_HIGH:@ref.[0-9]+]] = {{.*}}, align 4 +// CHECK: [[LOW_HIGH_REF:@const.[0-9]+]] = {{.*}} [[LOW_HIGH]] #[derive(Copy, Clone)] diff --git a/src/test/codegen/enum-bounds-check.rs b/src/test/codegen/enum-bounds-check.rs new file mode 100644 index 0000000000..4cfb5a752d --- /dev/null +++ b/src/test/codegen/enum-bounds-check.rs @@ -0,0 +1,24 @@ +// Copyright 2016 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +// compile-flags: -O + +#![crate_type = "lib"] + +pub enum Foo { + A, B +} + +// CHECK-LABEL: @lookup +#[no_mangle] +pub fn lookup(buf: &[u8; 2], f: Foo) -> u8 { + // CHECK-NOT: panic_bounds_check + buf[f as usize] +} diff --git a/src/test/codegen/issue-32364.rs b/src/test/codegen/issue-32364.rs index 926987be0e..401253a315 100644 --- a/src/test/codegen/issue-32364.rs +++ b/src/test/codegen/issue-32364.rs @@ -8,6 +8,9 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. +// ignore-arm +// ignore-aarch64 + // compile-flags: -C no-prepopulate-passes struct Foo; diff --git a/src/test/codegen/lifetime_start_end.rs b/src/test/codegen/lifetime_start_end.rs index cf91e7a8bc..81f6cf309d 100644 --- a/src/test/codegen/lifetime_start_end.rs +++ b/src/test/codegen/lifetime_start_end.rs @@ -30,11 +30,11 @@ pub fn test() { // CHECK: [[S_b:%[0-9]+]] = bitcast %"2.std::option::Option"** %b to i8* // CHECK: call void @llvm.lifetime.start(i{{[0-9 ]+}}, i8* [[S_b]]) -// CHECK: [[S_tmp2:%[0-9]+]] = bitcast %"2.std::option::Option"* %tmp2 to i8* -// CHECK: call void @llvm.lifetime.start(i{{[0-9 ]+}}, i8* [[S_tmp2]]) +// CHECK: [[S__5:%[0-9]+]] = bitcast %"2.std::option::Option"* %_5 to i8* +// CHECK: call void @llvm.lifetime.start(i{{[0-9 ]+}}, i8* [[S__5]]) -// CHECK: [[E_tmp2:%[0-9]+]] = bitcast %"2.std::option::Option"* %tmp2 to i8* -// CHECK: call void @llvm.lifetime.end(i{{[0-9 ]+}}, i8* [[E_tmp2]]) +// CHECK: [[E__5:%[0-9]+]] = bitcast %"2.std::option::Option"* %_5 to i8* +// CHECK: call void @llvm.lifetime.end(i{{[0-9 ]+}}, i8* [[E__5]]) // CHECK: [[E_b:%[0-9]+]] = bitcast %"2.std::option::Option"** %b to i8* // CHECK: call void @llvm.lifetime.end(i{{[0-9 ]+}}, i8* [[E_b]]) diff --git a/src/test/codegen/zip.rs b/src/test/codegen/zip.rs index 6c956364bf..d0051c5165 100644 --- a/src/test/codegen/zip.rs +++ b/src/test/codegen/zip.rs @@ -20,3 +20,12 @@ pub fn zip_copy(xs: &[u8], ys: &mut [u8]) { *y = *x; } } + +// CHECK-LABEL: @zip_copy_mapped +#[no_mangle] +pub fn zip_copy_mapped(xs: &[u8], ys: &mut [u8]) { +// CHECK: memcpy + for (x, y) in xs.iter().map(|&x| x).zip(ys) { + *y = x; + } +} diff --git a/src/test/compile-fail-fulldeps/auxiliary/macro_crate_test.rs b/src/test/compile-fail-fulldeps/auxiliary/macro_crate_test.rs index 5b1ecfed24..409f9dbf03 100644 --- a/src/test/compile-fail-fulldeps/auxiliary/macro_crate_test.rs +++ b/src/test/compile-fail-fulldeps/auxiliary/macro_crate_test.rs @@ -10,7 +10,6 @@ // force-host -#![feature(dotdot_in_tuple_patterns)] #![feature(plugin_registrar, quote, rustc_private)] extern crate syntax; @@ -56,8 +55,7 @@ fn expand_make_a_1(cx: &mut ExtCtxt, sp: Span, tts: &[TokenTree]) fn expand_identity(cx: &mut ExtCtxt, _span: Span, tts: &[TokenTree]) -> Box { // Parse an expression and emit it unchanged. - let mut parser = parse::new_parser_from_tts(cx.parse_sess(), - cx.cfg(), tts.to_vec()); + let mut parser = parse::new_parser_from_tts(cx.parse_sess(), tts.to_vec()); let expr = parser.parse_expr().unwrap(); MacEager::expr(quote_expr!(&mut *cx, $expr)) } diff --git a/src/test/compile-fail-fulldeps/derive-no-std-not-supported.rs b/src/test/compile-fail-fulldeps/derive-no-std-not-supported.rs index 01c81a8bbc..6ae5544d68 100644 --- a/src/test/compile-fail-fulldeps/derive-no-std-not-supported.rs +++ b/src/test/compile-fail-fulldeps/derive-no-std-not-supported.rs @@ -10,7 +10,6 @@ #![no_std] -extern crate core; extern crate rand; extern crate serialize as rustc_serialize; diff --git a/src/test/compile-fail-fulldeps/dropck_tarena_cycle_checked.rs b/src/test/compile-fail-fulldeps/dropck_tarena_cycle_checked.rs index d36293a484..bbdc59c843 100644 --- a/src/test/compile-fail-fulldeps/dropck_tarena_cycle_checked.rs +++ b/src/test/compile-fail-fulldeps/dropck_tarena_cycle_checked.rs @@ -123,5 +123,5 @@ fn f<'a>(arena: &'a TypedArena>) { fn main() { let arena = TypedArena::new(); - f(&arena); //~ ERROR `arena` does not live long enough -} + f(&arena); +} //~ ERROR `arena` does not live long enough diff --git a/src/test/compile-fail-fulldeps/dropck_tarena_unsound_drop.rs b/src/test/compile-fail-fulldeps/dropck_tarena_unsound_drop.rs index 6cbed34c7a..46cb760557 100644 --- a/src/test/compile-fail-fulldeps/dropck_tarena_unsound_drop.rs +++ b/src/test/compile-fail-fulldeps/dropck_tarena_unsound_drop.rs @@ -46,5 +46,6 @@ fn f<'a>(_arena: &'a TypedArena>) {} fn main() { let arena: TypedArena = TypedArena::new(); - f(&arena); //~ ERROR `arena` does not live long enough -} + f(&arena); +} //~ ERROR `arena` does not live long enough + diff --git a/src/test/compile-fail-fulldeps/issue-18986.rs b/src/test/compile-fail-fulldeps/issue-18986.rs index 3c32cb947b..95af376054 100644 --- a/src/test/compile-fail-fulldeps/issue-18986.rs +++ b/src/test/compile-fail-fulldeps/issue-18986.rs @@ -15,6 +15,6 @@ pub use use_from_trait_xc::Trait; fn main() { match () { - Trait { x: 42 } => () //~ ERROR expected variant, struct or type alias, found trait `Trait` + Trait { x: 42 } => () //~ ERROR expected struct, variant or union type, found trait `Trait` } } diff --git a/src/test/compile-fail-fulldeps/macro-crate-doesnt-resolve.rs b/src/test/compile-fail-fulldeps/macro-crate-doesnt-resolve.rs index 1fbde00a3d..f563a1f88d 100644 --- a/src/test/compile-fail-fulldeps/macro-crate-doesnt-resolve.rs +++ b/src/test/compile-fail-fulldeps/macro-crate-doesnt-resolve.rs @@ -14,6 +14,5 @@ extern crate macro_crate_test; fn main() { - macro_crate_test::foo(); - //~^ ERROR failed to resolve. Use of undeclared type or module `macro_crate_test` + macro_crate_test::foo(); //~ ERROR unresolved name } diff --git a/src/test/compile-fail-fulldeps/macro-crate-unknown-crate.rs b/src/test/compile-fail-fulldeps/no-link-unknown-crate.rs similarity index 95% rename from src/test/compile-fail-fulldeps/macro-crate-unknown-crate.rs rename to src/test/compile-fail-fulldeps/no-link-unknown-crate.rs index 65657eea1e..8e4692bdee 100644 --- a/src/test/compile-fail-fulldeps/macro-crate-unknown-crate.rs +++ b/src/test/compile-fail-fulldeps/no-link-unknown-crate.rs @@ -8,7 +8,7 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -#[macro_use] #[no_link] +#[no_link] extern crate doesnt_exist; //~ ERROR can't find crate fn main() {} diff --git a/src/test/compile-fail-fulldeps/rustc-macro/at-the-root.rs b/src/test/compile-fail-fulldeps/proc-macro/at-the-root.rs similarity index 73% rename from src/test/compile-fail-fulldeps/rustc-macro/at-the-root.rs rename to src/test/compile-fail-fulldeps/proc-macro/at-the-root.rs index 46724523d1..b03e1e4f91 100644 --- a/src/test/compile-fail-fulldeps/rustc-macro/at-the-root.rs +++ b/src/test/compile-fail-fulldeps/proc-macro/at-the-root.rs @@ -8,15 +8,15 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -#![crate_type = "rustc-macro"] -#![feature(rustc_macro)] +#![crate_type = "proc-macro"] +#![feature(proc_macro)] -extern crate rustc_macro; +extern crate proc_macro; -pub mod a { //~ `rustc-macro` crate types cannot export any items - use rustc_macro::TokenStream; +pub mod a { //~ `proc-macro` crate types cannot export any items + use proc_macro::TokenStream; - #[rustc_macro_derive(B)] + #[proc_macro_derive(B)] pub fn bar(a: TokenStream) -> TokenStream { //~^ ERROR: must currently reside in the root of the crate a diff --git a/src/test/compile-fail-fulldeps/proc-macro/attribute.rs b/src/test/compile-fail-fulldeps/proc-macro/attribute.rs new file mode 100644 index 0000000000..d1b2aa330e --- /dev/null +++ b/src/test/compile-fail-fulldeps/proc-macro/attribute.rs @@ -0,0 +1,46 @@ +// Copyright 2016 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +#![crate_type = "proc-macro"] +#![feature(proc_macro)] + +extern crate proc_macro; + +#[proc_macro_derive] +//~^ ERROR: attribute must be of form: #[proc_macro_derive(TraitName)] +pub fn foo1(input: proc_macro::TokenStream) -> proc_macro::TokenStream { + input +} + +#[proc_macro_derive = "foo"] +//~^ ERROR: attribute must be of form: #[proc_macro_derive(TraitName)] +pub fn foo2(input: proc_macro::TokenStream) -> proc_macro::TokenStream { + input +} + +#[proc_macro_derive( + a = "b" +)] +//~^^ ERROR: must only be one word +pub fn foo3(input: proc_macro::TokenStream) -> proc_macro::TokenStream { + input +} + +#[proc_macro_derive(b, c)] +//~^ ERROR: attribute must only have one argument +pub fn foo4(input: proc_macro::TokenStream) -> proc_macro::TokenStream { + input +} + +#[proc_macro_derive(d(e))] +//~^ ERROR: must only be one word +pub fn foo5(input: proc_macro::TokenStream) -> proc_macro::TokenStream { + input +} diff --git a/src/test/compile-fail-fulldeps/rustc-macro/auxiliary/derive-a.rs b/src/test/compile-fail-fulldeps/proc-macro/auxiliary/derive-a.rs similarity index 77% rename from src/test/compile-fail-fulldeps/rustc-macro/auxiliary/derive-a.rs rename to src/test/compile-fail-fulldeps/proc-macro/auxiliary/derive-a.rs index ff00a9d96a..4aa4238611 100644 --- a/src/test/compile-fail-fulldeps/rustc-macro/auxiliary/derive-a.rs +++ b/src/test/compile-fail-fulldeps/proc-macro/auxiliary/derive-a.rs @@ -11,15 +11,15 @@ // force-host // no-prefer-dynamic -#![feature(rustc_macro)] -#![feature(rustc_macro_lib)] -#![crate_type = "rustc-macro"] +#![feature(proc_macro)] +#![feature(proc_macro_lib)] +#![crate_type = "proc-macro"] -extern crate rustc_macro; +extern crate proc_macro; -use rustc_macro::TokenStream; +use proc_macro::TokenStream; -#[rustc_macro_derive(A)] +#[proc_macro_derive(A)] pub fn derive_a(input: TokenStream) -> TokenStream { input } diff --git a/src/test/compile-fail-fulldeps/rustc-macro/auxiliary/derive-bad.rs b/src/test/compile-fail-fulldeps/proc-macro/auxiliary/derive-bad.rs similarity index 78% rename from src/test/compile-fail-fulldeps/rustc-macro/auxiliary/derive-bad.rs rename to src/test/compile-fail-fulldeps/proc-macro/auxiliary/derive-bad.rs index 5dd42d28b7..aae8b63e25 100644 --- a/src/test/compile-fail-fulldeps/rustc-macro/auxiliary/derive-bad.rs +++ b/src/test/compile-fail-fulldeps/proc-macro/auxiliary/derive-bad.rs @@ -11,15 +11,15 @@ // no-prefer-dynamic // force-host -#![feature(rustc_macro)] -#![feature(rustc_macro_lib)] -#![crate_type = "rustc-macro"] +#![feature(proc_macro)] +#![feature(proc_macro_lib)] +#![crate_type = "proc-macro"] -extern crate rustc_macro; +extern crate proc_macro; -use rustc_macro::TokenStream; +use proc_macro::TokenStream; -#[rustc_macro_derive(A)] +#[proc_macro_derive(A)] pub fn derive_a(_input: TokenStream) -> TokenStream { "struct A { inner }".parse().unwrap() } diff --git a/src/test/compile-fail-fulldeps/rustc-macro/auxiliary/derive-panic.rs b/src/test/compile-fail-fulldeps/proc-macro/auxiliary/derive-panic.rs similarity index 77% rename from src/test/compile-fail-fulldeps/rustc-macro/auxiliary/derive-panic.rs rename to src/test/compile-fail-fulldeps/proc-macro/auxiliary/derive-panic.rs index d867082ed5..f426fe5437 100644 --- a/src/test/compile-fail-fulldeps/rustc-macro/auxiliary/derive-panic.rs +++ b/src/test/compile-fail-fulldeps/proc-macro/auxiliary/derive-panic.rs @@ -11,15 +11,15 @@ // no-prefer-dynamic // force-host -#![feature(rustc_macro)] -#![feature(rustc_macro_lib)] -#![crate_type = "rustc-macro"] +#![feature(proc_macro)] +#![feature(proc_macro_lib)] +#![crate_type = "proc-macro"] -extern crate rustc_macro; +extern crate proc_macro; -use rustc_macro::TokenStream; +use proc_macro::TokenStream; -#[rustc_macro_derive(A)] +#[proc_macro_derive(A)] pub fn derive_a(_input: TokenStream) -> TokenStream { panic!("nope!"); } diff --git a/src/test/compile-fail-fulldeps/rustc-macro/auxiliary/derive-unstable-2.rs b/src/test/compile-fail-fulldeps/proc-macro/auxiliary/derive-unstable-2.rs similarity index 78% rename from src/test/compile-fail-fulldeps/rustc-macro/auxiliary/derive-unstable-2.rs rename to src/test/compile-fail-fulldeps/proc-macro/auxiliary/derive-unstable-2.rs index 9eebad8975..d8952e3478 100644 --- a/src/test/compile-fail-fulldeps/rustc-macro/auxiliary/derive-unstable-2.rs +++ b/src/test/compile-fail-fulldeps/proc-macro/auxiliary/derive-unstable-2.rs @@ -11,15 +11,15 @@ // force-host // no-prefer-dynamic -#![feature(rustc_macro)] -#![feature(rustc_macro_lib)] -#![crate_type = "rustc-macro"] +#![feature(proc_macro)] +#![feature(proc_macro_lib)] +#![crate_type = "proc-macro"] -extern crate rustc_macro; +extern crate proc_macro; -use rustc_macro::TokenStream; +use proc_macro::TokenStream; -#[rustc_macro_derive(Unstable)] +#[proc_macro_derive(Unstable)] pub fn derive(_input: TokenStream) -> TokenStream { " diff --git a/src/test/compile-fail-fulldeps/rustc-macro/auxiliary/derive-unstable.rs b/src/test/compile-fail-fulldeps/proc-macro/auxiliary/derive-unstable.rs similarity index 78% rename from src/test/compile-fail-fulldeps/rustc-macro/auxiliary/derive-unstable.rs rename to src/test/compile-fail-fulldeps/proc-macro/auxiliary/derive-unstable.rs index f4a1ec9970..1187b5102e 100644 --- a/src/test/compile-fail-fulldeps/rustc-macro/auxiliary/derive-unstable.rs +++ b/src/test/compile-fail-fulldeps/proc-macro/auxiliary/derive-unstable.rs @@ -11,15 +11,15 @@ // force-host // no-prefer-dynamic -#![feature(rustc_macro)] -#![feature(rustc_macro_lib)] -#![crate_type = "rustc-macro"] +#![feature(proc_macro)] +#![feature(proc_macro_lib)] +#![crate_type = "proc-macro"] -extern crate rustc_macro; +extern crate proc_macro; -use rustc_macro::TokenStream; +use proc_macro::TokenStream; -#[rustc_macro_derive(Unstable)] +#[proc_macro_derive(Unstable)] pub fn derive(_input: TokenStream) -> TokenStream { "unsafe fn foo() -> u32 { ::std::intrinsics::init() }".parse().unwrap() diff --git a/src/test/compile-fail-fulldeps/rustc-macro/cannot-link.rs b/src/test/compile-fail-fulldeps/proc-macro/cannot-link.rs similarity index 87% rename from src/test/compile-fail-fulldeps/rustc-macro/cannot-link.rs rename to src/test/compile-fail-fulldeps/proc-macro/cannot-link.rs index 1f135330a9..f6f1be37fc 100644 --- a/src/test/compile-fail-fulldeps/rustc-macro/cannot-link.rs +++ b/src/test/compile-fail-fulldeps/proc-macro/cannot-link.rs @@ -11,6 +11,6 @@ // aux-build:derive-a.rs extern crate derive_a; -//~^ ERROR: crates of the `rustc-macro` crate type cannot be linked at runtime +//~^ ERROR: crates of the `proc-macro` crate type cannot be linked at runtime fn main() {} diff --git a/src/test/compile-fail-fulldeps/rustc-macro/define-two.rs b/src/test/compile-fail-fulldeps/proc-macro/define-two.rs similarity index 74% rename from src/test/compile-fail-fulldeps/rustc-macro/define-two.rs rename to src/test/compile-fail-fulldeps/proc-macro/define-two.rs index e4f21dc238..420249b258 100644 --- a/src/test/compile-fail-fulldeps/rustc-macro/define-two.rs +++ b/src/test/compile-fail-fulldeps/proc-macro/define-two.rs @@ -10,19 +10,19 @@ // no-prefer-dynamic -#![crate_type = "rustc-macro"] -#![feature(rustc_macro)] +#![crate_type = "proc-macro"] +#![feature(proc_macro)] -extern crate rustc_macro; +extern crate proc_macro; -use rustc_macro::TokenStream; +use proc_macro::TokenStream; -#[rustc_macro_derive(A)] +#[proc_macro_derive(A)] pub fn foo(input: TokenStream) -> TokenStream { input } -#[rustc_macro_derive(A)] //~ ERROR: derive mode defined twice in this crate +#[proc_macro_derive(A)] //~ ERROR: derive mode defined twice in this crate pub fn bar(input: TokenStream) -> TokenStream { input } diff --git a/src/test/compile-fail-fulldeps/rustc-macro/derive-bad.rs b/src/test/compile-fail-fulldeps/proc-macro/derive-bad.rs similarity index 96% rename from src/test/compile-fail-fulldeps/rustc-macro/derive-bad.rs rename to src/test/compile-fail-fulldeps/proc-macro/derive-bad.rs index f3a73af299..4cc6b9f984 100644 --- a/src/test/compile-fail-fulldeps/rustc-macro/derive-bad.rs +++ b/src/test/compile-fail-fulldeps/proc-macro/derive-bad.rs @@ -10,7 +10,7 @@ // aux-build:derive-bad.rs -#![feature(rustc_macro)] +#![feature(proc_macro)] #[macro_use] extern crate derive_bad; diff --git a/src/test/compile-fail-fulldeps/rustc-macro/derive-still-gated.rs b/src/test/compile-fail-fulldeps/proc-macro/derive-still-gated.rs similarity index 96% rename from src/test/compile-fail-fulldeps/rustc-macro/derive-still-gated.rs rename to src/test/compile-fail-fulldeps/proc-macro/derive-still-gated.rs index a46d79f517..eb0bb00be9 100644 --- a/src/test/compile-fail-fulldeps/rustc-macro/derive-still-gated.rs +++ b/src/test/compile-fail-fulldeps/proc-macro/derive-still-gated.rs @@ -10,7 +10,7 @@ // aux-build:derive-a.rs -#![feature(rustc_macro)] +#![feature(proc_macro)] #![allow(warnings)] #[macro_use] diff --git a/src/test/compile-fail-fulldeps/rustc-macro/expand-to-unstable-2.rs b/src/test/compile-fail-fulldeps/proc-macro/expand-to-unstable-2.rs similarity index 96% rename from src/test/compile-fail-fulldeps/rustc-macro/expand-to-unstable-2.rs rename to src/test/compile-fail-fulldeps/proc-macro/expand-to-unstable-2.rs index 14c3d84e75..23dcbe03b5 100644 --- a/src/test/compile-fail-fulldeps/rustc-macro/expand-to-unstable-2.rs +++ b/src/test/compile-fail-fulldeps/proc-macro/expand-to-unstable-2.rs @@ -10,7 +10,7 @@ // aux-build:derive-unstable-2.rs -#![feature(rustc_macro)] +#![feature(proc_macro)] #![allow(warnings)] #[macro_use] diff --git a/src/test/compile-fail-fulldeps/rustc-macro/expand-to-unstable.rs b/src/test/compile-fail-fulldeps/proc-macro/expand-to-unstable.rs similarity index 96% rename from src/test/compile-fail-fulldeps/rustc-macro/expand-to-unstable.rs rename to src/test/compile-fail-fulldeps/proc-macro/expand-to-unstable.rs index aa9aaa8115..fb86f6f1b6 100644 --- a/src/test/compile-fail-fulldeps/rustc-macro/expand-to-unstable.rs +++ b/src/test/compile-fail-fulldeps/proc-macro/expand-to-unstable.rs @@ -10,7 +10,7 @@ // aux-build:derive-unstable.rs -#![feature(rustc_macro)] +#![feature(proc_macro)] #![allow(warnings)] #[macro_use] diff --git a/src/test/compile-fail-fulldeps/rustc-macro/export-macro.rs b/src/test/compile-fail-fulldeps/proc-macro/export-macro.rs similarity index 79% rename from src/test/compile-fail-fulldeps/rustc-macro/export-macro.rs rename to src/test/compile-fail-fulldeps/proc-macro/export-macro.rs index 759f3d32e1..48b73e7333 100644 --- a/src/test/compile-fail-fulldeps/rustc-macro/export-macro.rs +++ b/src/test/compile-fail-fulldeps/proc-macro/export-macro.rs @@ -8,10 +8,10 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -// error-pattern: cannot export macro_rules! macros from a `rustc-macro` crate +// error-pattern: cannot export macro_rules! macros from a `proc-macro` crate -#![crate_type = "rustc-macro"] -#![feature(rustc_macro)] +#![crate_type = "proc-macro"] +#![feature(proc_macro)] #[macro_export] macro_rules! foo { diff --git a/src/test/compile-fail-fulldeps/rustc-macro/exports.rs b/src/test/compile-fail-fulldeps/proc-macro/exports.rs similarity index 95% rename from src/test/compile-fail-fulldeps/rustc-macro/exports.rs rename to src/test/compile-fail-fulldeps/proc-macro/exports.rs index e985356dc5..41b94d04e8 100644 --- a/src/test/compile-fail-fulldeps/rustc-macro/exports.rs +++ b/src/test/compile-fail-fulldeps/proc-macro/exports.rs @@ -8,7 +8,7 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -#![crate_type = "rustc-macro"] +#![crate_type = "proc-macro"] #![allow(warnings)] pub fn a() {} //~ ERROR: cannot export any items diff --git a/src/test/compile-fail-fulldeps/rustc-macro/feature-gate-1.rs b/src/test/compile-fail-fulldeps/proc-macro/feature-gate-1.rs similarity index 83% rename from src/test/compile-fail-fulldeps/rustc-macro/feature-gate-1.rs rename to src/test/compile-fail-fulldeps/proc-macro/feature-gate-1.rs index 86afc08cae..f5618fc642 100644 --- a/src/test/compile-fail-fulldeps/rustc-macro/feature-gate-1.rs +++ b/src/test/compile-fail-fulldeps/proc-macro/feature-gate-1.rs @@ -8,6 +8,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -// error-pattern: the `rustc-macro` crate type is experimental +// error-pattern: the `proc-macro` crate type is experimental -#![crate_type = "rustc-macro"] +#![crate_type = "proc-macro"] diff --git a/src/test/compile-fail-fulldeps/rustc-macro/feature-gate-2.rs b/src/test/compile-fail-fulldeps/proc-macro/feature-gate-2.rs similarity index 87% rename from src/test/compile-fail-fulldeps/rustc-macro/feature-gate-2.rs rename to src/test/compile-fail-fulldeps/proc-macro/feature-gate-2.rs index 1a19f6046d..9c4053266f 100644 --- a/src/test/compile-fail-fulldeps/rustc-macro/feature-gate-2.rs +++ b/src/test/compile-fail-fulldeps/proc-macro/feature-gate-2.rs @@ -8,6 +8,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -extern crate rustc_macro; //~ ERROR: use of unstable library feature +extern crate proc_macro; //~ ERROR: use of unstable library feature fn main() {} diff --git a/src/test/compile-fail-fulldeps/rustc-macro/feature-gate-3.rs b/src/test/compile-fail-fulldeps/proc-macro/feature-gate-3.rs similarity index 83% rename from src/test/compile-fail-fulldeps/rustc-macro/feature-gate-3.rs rename to src/test/compile-fail-fulldeps/proc-macro/feature-gate-3.rs index 9f47f07bd0..bb6b575962 100644 --- a/src/test/compile-fail-fulldeps/rustc-macro/feature-gate-3.rs +++ b/src/test/compile-fail-fulldeps/proc-macro/feature-gate-3.rs @@ -8,8 +8,8 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -#![crate_type = "rustc-macro"] +#![crate_type = "proc-macro"] -#[rustc_macro_derive(Foo)] //~ ERROR: is an experimental feature +#[proc_macro_derive(Foo)] //~ ERROR: is an experimental feature pub fn foo() { } diff --git a/src/test/compile-fail-fulldeps/rustc-macro/feature-gate-4.rs b/src/test/compile-fail-fulldeps/proc-macro/feature-gate-4.rs similarity index 100% rename from src/test/compile-fail-fulldeps/rustc-macro/feature-gate-4.rs rename to src/test/compile-fail-fulldeps/proc-macro/feature-gate-4.rs diff --git a/src/test/compile-fail-fulldeps/rustc-macro/feature-gate-5.rs b/src/test/compile-fail-fulldeps/proc-macro/feature-gate-5.rs similarity index 87% rename from src/test/compile-fail-fulldeps/rustc-macro/feature-gate-5.rs rename to src/test/compile-fail-fulldeps/proc-macro/feature-gate-5.rs index e44b29a170..672579ce8f 100644 --- a/src/test/compile-fail-fulldeps/rustc-macro/feature-gate-5.rs +++ b/src/test/compile-fail-fulldeps/proc-macro/feature-gate-5.rs @@ -8,5 +8,5 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -#[cfg(rustc_macro)] //~ ERROR: experimental and subject to change +#[cfg(proc_macro)] //~ ERROR: experimental and subject to change fn foo() {} diff --git a/src/test/compile-fail-fulldeps/proc-macro/illegal-proc-macro-derive-use.rs b/src/test/compile-fail-fulldeps/proc-macro/illegal-proc-macro-derive-use.rs new file mode 100644 index 0000000000..405994b36e --- /dev/null +++ b/src/test/compile-fail-fulldeps/proc-macro/illegal-proc-macro-derive-use.rs @@ -0,0 +1,27 @@ +// Copyright 2016 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +#![feature(proc_macro)] + +extern crate proc_macro; + +#[proc_macro_derive(Foo)] +//~^ ERROR: only usable with crates of the `proc-macro` crate type +pub fn foo(a: proc_macro::TokenStream) -> proc_macro::TokenStream { + a +} + +// Issue #37590 +#[proc_macro_derive(Foo)] +//~^ ERROR: the `#[proc_macro_derive]` attribute may only be used on bare functions +pub struct Foo { +} + +fn main() {} diff --git a/src/test/compile-fail-fulldeps/rustc-macro/import.rs b/src/test/compile-fail-fulldeps/proc-macro/import.rs similarity index 96% rename from src/test/compile-fail-fulldeps/rustc-macro/import.rs rename to src/test/compile-fail-fulldeps/proc-macro/import.rs index c1d0823cb6..8f907183cc 100644 --- a/src/test/compile-fail-fulldeps/rustc-macro/import.rs +++ b/src/test/compile-fail-fulldeps/proc-macro/import.rs @@ -10,7 +10,7 @@ // aux-build:derive-a.rs -#![feature(rustc_macro)] +#![feature(proc_macro)] #![allow(warnings)] #[macro_use] diff --git a/src/test/compile-fail-fulldeps/rustc-macro/load-panic.rs b/src/test/compile-fail-fulldeps/proc-macro/load-panic.rs similarity index 96% rename from src/test/compile-fail-fulldeps/rustc-macro/load-panic.rs rename to src/test/compile-fail-fulldeps/proc-macro/load-panic.rs index 0d08d27c38..39c27e82fa 100644 --- a/src/test/compile-fail-fulldeps/rustc-macro/load-panic.rs +++ b/src/test/compile-fail-fulldeps/proc-macro/load-panic.rs @@ -10,7 +10,7 @@ // aux-build:derive-panic.rs -#![feature(rustc_macro)] +#![feature(proc_macro)] #[macro_use] extern crate derive_panic; diff --git a/src/test/compile-fail-fulldeps/rustc-macro/shadow-builtin.rs b/src/test/compile-fail-fulldeps/proc-macro/shadow-builtin.rs similarity index 80% rename from src/test/compile-fail-fulldeps/rustc-macro/shadow-builtin.rs rename to src/test/compile-fail-fulldeps/proc-macro/shadow-builtin.rs index 1353a234b4..5cb2cc59aa 100644 --- a/src/test/compile-fail-fulldeps/rustc-macro/shadow-builtin.rs +++ b/src/test/compile-fail-fulldeps/proc-macro/shadow-builtin.rs @@ -8,14 +8,14 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -#![crate_type = "rustc-macro"] -#![feature(rustc_macro)] +#![crate_type = "proc-macro"] +#![feature(proc_macro)] -extern crate rustc_macro; +extern crate proc_macro; -use rustc_macro::TokenStream; +use proc_macro::TokenStream; -#[rustc_macro_derive(PartialEq)] +#[proc_macro_derive(PartialEq)] //~^ ERROR: cannot override a built-in #[derive] mode pub fn foo(input: TokenStream) -> TokenStream { input diff --git a/src/test/compile-fail-fulldeps/rustc-macro/shadow.rs b/src/test/compile-fail-fulldeps/proc-macro/shadow.rs similarity index 81% rename from src/test/compile-fail-fulldeps/rustc-macro/shadow.rs rename to src/test/compile-fail-fulldeps/proc-macro/shadow.rs index 33330ed8f6..a04756ca19 100644 --- a/src/test/compile-fail-fulldeps/rustc-macro/shadow.rs +++ b/src/test/compile-fail-fulldeps/proc-macro/shadow.rs @@ -9,13 +9,12 @@ // except according to those terms. // aux-build:derive-a.rs -// aux-build:derive-a-2.rs -#![feature(rustc_macro)] +#![feature(proc_macro)] #[macro_use] extern crate derive_a; #[macro_use] -extern crate derive_a_2; //~ ERROR: cannot shadow existing derive mode `A` +extern crate derive_a; //~ ERROR `derive_a` has already been defined fn main() {} diff --git a/src/test/compile-fail-fulldeps/rustc-macro/signature.rs b/src/test/compile-fail-fulldeps/proc-macro/signature.rs similarity index 78% rename from src/test/compile-fail-fulldeps/rustc-macro/signature.rs rename to src/test/compile-fail-fulldeps/proc-macro/signature.rs index 9662cc69e1..468c970599 100644 --- a/src/test/compile-fail-fulldeps/rustc-macro/signature.rs +++ b/src/test/compile-fail-fulldeps/proc-macro/signature.rs @@ -8,17 +8,17 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -#![crate_type = "rustc-macro"] -#![feature(rustc_macro)] +#![crate_type = "proc-macro"] +#![feature(proc_macro)] #![allow(warnings)] -extern crate rustc_macro; +extern crate proc_macro; -#[rustc_macro_derive(A)] +#[proc_macro_derive(A)] unsafe extern fn foo(a: i32, b: u32) -> u32 { //~^ ERROR: mismatched types //~| NOTE: expected normal fn, found unsafe fn - //~| NOTE: expected type `fn(rustc_macro::TokenStream) -> rustc_macro::TokenStream` + //~| NOTE: expected type `fn(proc_macro::TokenStream) -> proc_macro::TokenStream` //~| NOTE: found type `unsafe extern "C" fn(i32, u32) -> u32 {foo}` loop {} } diff --git a/src/test/compile-fail-fulldeps/rustc-macro/two-crate-types-1.rs b/src/test/compile-fail-fulldeps/proc-macro/two-crate-types-1.rs similarity index 83% rename from src/test/compile-fail-fulldeps/rustc-macro/two-crate-types-1.rs rename to src/test/compile-fail-fulldeps/proc-macro/two-crate-types-1.rs index 35f6149ad4..db646fb781 100644 --- a/src/test/compile-fail-fulldeps/rustc-macro/two-crate-types-1.rs +++ b/src/test/compile-fail-fulldeps/proc-macro/two-crate-types-1.rs @@ -8,7 +8,7 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -// error-pattern: cannot mix `rustc-macro` crate type with others +// error-pattern: cannot mix `proc-macro` crate type with others -#![crate_type = "rustc-macro"] +#![crate_type = "proc-macro"] #![crate_type = "rlib"] diff --git a/src/test/compile-fail-fulldeps/rustc-macro/two-crate-types-2.rs b/src/test/compile-fail-fulldeps/proc-macro/two-crate-types-2.rs similarity index 78% rename from src/test/compile-fail-fulldeps/rustc-macro/two-crate-types-2.rs rename to src/test/compile-fail-fulldeps/proc-macro/two-crate-types-2.rs index ec95e3e468..97b0f84460 100644 --- a/src/test/compile-fail-fulldeps/rustc-macro/two-crate-types-2.rs +++ b/src/test/compile-fail-fulldeps/proc-macro/two-crate-types-2.rs @@ -8,5 +8,5 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -// error-pattern: cannot mix `rustc-macro` crate type with others -// compile-flags: --crate-type rlib --crate-type rustc-macro +// error-pattern: cannot mix `proc-macro` crate type with others +// compile-flags: --crate-type rlib --crate-type proc-macro diff --git a/src/test/compile-fail-fulldeps/qquote.rs b/src/test/compile-fail-fulldeps/qquote.rs index 3e5d17e2ff..4a7033d44b 100644 --- a/src/test/compile-fail-fulldeps/qquote.rs +++ b/src/test/compile-fail-fulldeps/qquote.rs @@ -24,7 +24,7 @@ fn main() { let ps = syntax::parse::ParseSess::new(); let mut resolver = syntax::ext::base::DummyResolver; let mut cx = syntax::ext::base::ExtCtxt::new( - &ps, vec![], + &ps, syntax::ext::expand::ExpansionConfig::default("qquote".to_string()), &mut resolver); cx.bt_push(syntax::codemap::ExpnInfo { diff --git a/src/test/compile-fail-fulldeps/rustc-macro/attribute.rs b/src/test/compile-fail-fulldeps/rustc-macro/attribute.rs deleted file mode 100644 index 7740238aea..0000000000 --- a/src/test/compile-fail-fulldeps/rustc-macro/attribute.rs +++ /dev/null @@ -1,46 +0,0 @@ -// Copyright 2016 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution and at -// http://rust-lang.org/COPYRIGHT. -// -// Licensed under the Apache License, Version 2.0 or the MIT license -// , at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - -#![crate_type = "rustc-macro"] -#![feature(rustc_macro)] - -extern crate rustc_macro; - -#[rustc_macro_derive] -//~^ ERROR: attribute must be of form: #[rustc_macro_derive(TraitName)] -pub fn foo1(input: rustc_macro::TokenStream) -> rustc_macro::TokenStream { - input -} - -#[rustc_macro_derive = "foo"] -//~^ ERROR: attribute must be of form: #[rustc_macro_derive(TraitName)] -pub fn foo2(input: rustc_macro::TokenStream) -> rustc_macro::TokenStream { - input -} - -#[rustc_macro_derive( - a = "b" -)] -//~^^ ERROR: must only be one word -pub fn foo3(input: rustc_macro::TokenStream) -> rustc_macro::TokenStream { - input -} - -#[rustc_macro_derive(b, c)] -//~^ ERROR: attribute must only have one argument -pub fn foo4(input: rustc_macro::TokenStream) -> rustc_macro::TokenStream { - input -} - -#[rustc_macro_derive(d(e))] -//~^ ERROR: must only be one word -pub fn foo5(input: rustc_macro::TokenStream) -> rustc_macro::TokenStream { - input -} diff --git a/src/test/compile-fail/E0002.rs b/src/test/compile-fail/E0004-2.rs similarity index 94% rename from src/test/compile-fail/E0002.rs rename to src/test/compile-fail/E0004-2.rs index 0e94c9595d..824b86cfa8 100644 --- a/src/test/compile-fail/E0002.rs +++ b/src/test/compile-fail/E0004-2.rs @@ -11,5 +11,5 @@ fn main() { let x = Some(1); - match x { } //~ ERROR E0002 + match x { } //~ ERROR E0004 } diff --git a/src/test/compile-fail/E0007.rs b/src/test/compile-fail/E0007.rs index 4be115b8af..b72b5e3b28 100644 --- a/src/test/compile-fail/E0007.rs +++ b/src/test/compile-fail/E0007.rs @@ -15,6 +15,7 @@ fn main() { //~^ ERROR E0007 //~| NOTE binds an already bound by-move value by moving it //~| ERROR E0303 + //~| NOTE not allowed after `@` None => {}, } } diff --git a/src/test/compile-fail/E0025.rs b/src/test/compile-fail/E0025.rs index 3f5922cdc0..1d15cef8bc 100644 --- a/src/test/compile-fail/E0025.rs +++ b/src/test/compile-fail/E0025.rs @@ -15,5 +15,8 @@ struct Foo { fn main() { let x = Foo { a:1, b:2 }; - let Foo { a: x, a: y, b: 0 } = x; //~ ERROR E0025 + let Foo { a: x, a: y, b: 0 } = x; + //~^ ERROR field `a` bound multiple times in the pattern + //~| NOTE multiple uses of `a` in pattern + //~| NOTE first use of `a` } diff --git a/src/test/compile-fail/E0035.rs b/src/test/compile-fail/E0035.rs index 43f46e3578..9322d21d2a 100644 --- a/src/test/compile-fail/E0035.rs +++ b/src/test/compile-fail/E0035.rs @@ -17,4 +17,5 @@ impl Test { fn main() { let x = Test; x.method::(); //~ ERROR E0035 + //~| NOTE called with unneeded type parameters } diff --git a/src/test/compile-fail/E0036.rs b/src/test/compile-fail/E0036.rs index 35fd6e8942..ecb6dac66f 100644 --- a/src/test/compile-fail/E0036.rs +++ b/src/test/compile-fail/E0036.rs @@ -20,4 +20,5 @@ fn main() { let x = Test; let v = &[0]; x.method::(v); //~ ERROR E0036 + //~| NOTE Passed 2 type arguments, expected 1 } diff --git a/src/test/compile-fail/E0050.rs b/src/test/compile-fail/E0050.rs index 2f7dc96361..5c53d62709 100644 --- a/src/test/compile-fail/E0050.rs +++ b/src/test/compile-fail/E0050.rs @@ -9,13 +9,20 @@ // except according to those terms. trait Foo { - fn foo(&self, x: u8) -> bool; + fn foo(&self, x: u8) -> bool; //~ NOTE trait requires 2 parameters + fn bar(&self, x: u8, y: u8, z: u8); //~ NOTE trait requires 4 parameters + fn less(&self); //~ NOTE trait requires 1 parameter } struct Bar; impl Foo for Bar { fn foo(&self) -> bool { true } //~ ERROR E0050 + //~| NOTE expected 2 parameters, found 1 + fn bar(&self) { } //~ ERROR E0050 + //~| NOTE expected 4 parameters, found 1 + fn less(&self, x: u8, y: u8, z: u8) { } //~ ERROR E0050 + //~| NOTE expected 1 parameter, found 4 } fn main() { diff --git a/src/test/compile-fail/E0071.rs b/src/test/compile-fail/E0071.rs index c13ba7bf13..95653ae83e 100644 --- a/src/test/compile-fail/E0071.rs +++ b/src/test/compile-fail/E0071.rs @@ -9,13 +9,10 @@ // except according to those terms. enum Foo {} +type FooAlias = Foo; fn main() { - let u = Foo { value: 0 }; - //~^ ERROR `Foo` does not name a struct or a struct variant [E0071] - //~| NOTE not a struct - - let t = u32 { value: 4 }; - //~^ ERROR `u32` does not name a struct or a struct variant [E0071] + let u = FooAlias { value: 0 }; + //~^ ERROR expected struct, variant or union type, found enum `Foo` [E0071] //~| NOTE not a struct } diff --git a/src/test/compile-fail/E0164.rs b/src/test/compile-fail/E0164.rs index 1665a80bea..8d21cde84d 100644 --- a/src/test/compile-fail/E0164.rs +++ b/src/test/compile-fail/E0164.rs @@ -8,7 +8,13 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -enum Foo { B { i: u32 } } +#![feature(associated_consts)] + +enum Foo {} + +impl Foo { + const B: u8 = 0; +} fn bar(foo: Foo) -> u32 { match foo { diff --git a/src/test/compile-fail/E0198.rs b/src/test/compile-fail/E0198.rs new file mode 100644 index 0000000000..892989cc6a --- /dev/null +++ b/src/test/compile-fail/E0198.rs @@ -0,0 +1,18 @@ +// Copyright 2016 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +#![feature(optin_builtin_traits)] + +struct Foo; + +unsafe impl !Clone for Foo { } //~ ERROR negative implementations are not unsafe [E0198] + +fn main() { +} diff --git a/src/test/compile-fail/E0199.rs b/src/test/compile-fail/E0199.rs index 8bd3ffdf6f..1a5cd1941a 100644 --- a/src/test/compile-fail/E0199.rs +++ b/src/test/compile-fail/E0199.rs @@ -12,7 +12,8 @@ struct Foo; -unsafe impl !Clone for Foo { } //~ ERROR E0199 +trait Bar { } +unsafe impl Bar for Foo { } //~ ERROR implementing the trait `Bar` is not unsafe [E0199] fn main() { } diff --git a/src/test/compile-fail/E0220.rs b/src/test/compile-fail/E0220.rs index 17e2b18b37..c5a1824514 100644 --- a/src/test/compile-fail/E0220.rs +++ b/src/test/compile-fail/E0220.rs @@ -13,7 +13,8 @@ trait Trait { } type Foo = Trait; //~ ERROR E0220 - //~^ ERROR E0191 - + //~| NOTE associated type `F` not found + //~| ERROR E0191 + //~| NOTE missing associated type `Bar` value fn main() { } diff --git a/src/test/compile-fail/E0221.rs b/src/test/compile-fail/E0221.rs index 6510545804..aed2b4084e 100644 --- a/src/test/compile-fail/E0221.rs +++ b/src/test/compile-fail/E0221.rs @@ -12,17 +12,27 @@ trait T1 {} trait T2 {} trait Foo { - type A: T1; + type A: T1; //~ NOTE: ambiguous `A` from `Foo` } trait Bar : Foo { - type A: T2; + type A: T2; //~ NOTE: ambiguous `A` from `Bar` fn do_something() { let _: Self::A; //~^ ERROR E0221 //~| NOTE ambiguous associated type `A` - //~| NOTE associated type `Self` could derive from `Foo` - //~| NOTE associated type `Self` could derive from `Bar` + } +} + +trait T3 {} + +trait My : std::str::FromStr { + type Err: T3; //~ NOTE: ambiguous `Err` from `My` + fn test() { + let _: Self::Err; + //~^ ERROR E0221 + //~| NOTE ambiguous associated type `Err` + //~| NOTE associated type `Self` could derive from `std::str::FromStr` } } diff --git a/src/test/compile-fail/E0243.rs b/src/test/compile-fail/E0243.rs index 77c9856c26..4434723e12 100644 --- a/src/test/compile-fail/E0243.rs +++ b/src/test/compile-fail/E0243.rs @@ -11,7 +11,7 @@ struct Foo { x: T } struct Bar { x: Foo } //~^ ERROR E0243 - //~| NOTE expected 1 type arguments, found 0 + //~| NOTE expected 1 type argument, found 0 fn main() { } diff --git a/src/test/compile-fail/E0277.rs b/src/test/compile-fail/E0277.rs index 12f9417f94..e4cb50cd3f 100644 --- a/src/test/compile-fail/E0277.rs +++ b/src/test/compile-fail/E0277.rs @@ -19,6 +19,6 @@ fn some_func(foo: T) { fn main() { some_func(5i32); //~^ ERROR the trait bound `i32: Foo` is not satisfied - //~| NOTE trait `i32: Foo` not satisfied + //~| NOTE the trait `Foo` is not implemented for `i32` //~| NOTE required by `some_func` } diff --git a/src/test/compile-fail/E0297.rs b/src/test/compile-fail/E0297.rs index 32c129b22a..5792ba06eb 100644 --- a/src/test/compile-fail/E0297.rs +++ b/src/test/compile-fail/E0297.rs @@ -9,7 +9,7 @@ // except according to those terms. fn main() { - let xs : Vec> = vec!(Some(1), None); + let xs : Vec> = vec![Some(1), None]; for Some(x) in xs {} //~^ ERROR E0297 diff --git a/src/test/compile-fail/E0303.rs b/src/test/compile-fail/E0303.rs index 67947fd087..e631fe2a8a 100644 --- a/src/test/compile-fail/E0303.rs +++ b/src/test/compile-fail/E0303.rs @@ -10,8 +10,12 @@ fn main() { match Some("hi".to_string()) { - ref op_string_ref @ Some(s) => {}, //~ ERROR E0303 - //~^ ERROR E0009 + ref op_string_ref @ Some(s) => {}, + //~^ ERROR pattern bindings are not allowed after an `@` [E0303] + //~| NOTE not allowed after `@` + //~| ERROR E0009 + //~| NOTE by-move pattern here + //~| NOTE both by-ref and by-move used None => {}, } } diff --git a/src/test/compile-fail/E0408.rs b/src/test/compile-fail/E0408.rs index 43f6d9d757..d75f612482 100644 --- a/src/test/compile-fail/E0408.rs +++ b/src/test/compile-fail/E0408.rs @@ -12,7 +12,7 @@ fn main() { let x = Some(0); match x { - Some(y) | None => {} //~ ERROR E0408 - _ => () + Some(y) | None => {} //~ ERROR variable `y` from pattern #1 is not bound in pattern #2 + _ => () //~| NOTE pattern doesn't bind `y` } } diff --git a/src/test/compile-fail/allocator-dylib-is-system.rs b/src/test/compile-fail/allocator-dylib-is-system.rs index db7f304227..4c576de220 100644 --- a/src/test/compile-fail/allocator-dylib-is-system.rs +++ b/src/test/compile-fail/allocator-dylib-is-system.rs @@ -18,6 +18,8 @@ // system allocator. Do this by linking in jemalloc and making sure that we get // an error. +// ignore-emscripten FIXME: What "other allocator" should we use for emcc? + #![feature(alloc_jemalloc)] extern crate allocator_dylib; diff --git a/src/test/compile-fail/allocator-rust-dylib-is-jemalloc.rs b/src/test/compile-fail/allocator-rust-dylib-is-jemalloc.rs index 46ad226d25..02c271ab24 100644 --- a/src/test/compile-fail/allocator-rust-dylib-is-jemalloc.rs +++ b/src/test/compile-fail/allocator-rust-dylib-is-jemalloc.rs @@ -16,6 +16,8 @@ // Ensure that rust dynamic libraries use jemalloc as their allocator, verifying // by linking in the system allocator here and ensuring that we get a complaint. +// ignore-emscripten FIXME: What "other allocator" is correct for emscripten? + #![feature(alloc_system)] extern crate allocator_dylib2; diff --git a/src/test/compile-fail/associated-path-shl.rs b/src/test/compile-fail/associated-path-shl.rs new file mode 100644 index 0000000000..6bc110239c --- /dev/null +++ b/src/test/compile-fail/associated-path-shl.rs @@ -0,0 +1,20 @@ +// Copyright 2016 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +// Check that associated paths starting with `<<` are successfully parsed. + +fn main() { + let _: <::B>::C; //~ ERROR type name `A` is undefined or not in scope + let _ = <::B>::C; //~ ERROR type name `A` is undefined or not in scope + let <::B>::C; //~ ERROR type name `A` is undefined or not in scope + let 0 ... <::B>::C; //~ ERROR type name `A` is undefined or not in scope + //~^ ERROR only char and numeric types are allowed in range patterns + <::B>::C; //~ ERROR type name `A` is undefined or not in scope +} 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 a2a11c62bb..b33bbfd842 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 @@ -13,13 +13,19 @@ pub trait Vehicle { type Color; + //~^ NOTE ambiguous `Color` from `Vehicle` + //~| NOTE ambiguous `Color` from `Vehicle` + //~| NOTE ambiguous `Color` from `Vehicle` fn go(&self) { } } pub trait Box { type Color; - + //~^ NOTE ambiguous `Color` from `Box` + //~| NOTE ambiguous `Color` from `Box` + //~| NOTE ambiguous `Color` from `Box` + // fn mail(&self) { } } @@ -29,24 +35,18 @@ pub trait BoxCar : Box + Vehicle { fn dent(c: C, color: C::Color) { //~^ ERROR ambiguous associated type `Color` in bounds of `C` //~| NOTE ambiguous associated type `Color` - //~| NOTE could derive from `Vehicle` - //~| NOTE could derive from `Box` } 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 ambiguous associated type `Color` - //~| NOTE could derive from `Vehicle` - //~| NOTE could derive from `Box` //~| NOTE missing associated type `Color` value } fn paint(c: C, d: C::Color) { //~^ ERROR ambiguous associated type `Color` in bounds of `C` //~| NOTE ambiguous associated type `Color` - //~| NOTE could derive from `Vehicle` - //~| NOTE could derive from `Box` } pub fn main() { } 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 0846169646..5a19aecf66 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 @@ -32,5 +32,5 @@ fn ice(a: A) { let r = loop {}; r = r + a; //~^ ERROR the trait bound `(): Add` is not satisfied - //~| NOTE trait `(): Add` not satisfied + //~| NOTE the trait `Add` is not implemented for `()` } diff --git a/src/test/compile-fail/attempted-access-non-fatal.rs b/src/test/compile-fail/attempted-access-non-fatal.rs index 1d9249bc17..fe8e793ed7 100644 --- a/src/test/compile-fail/attempted-access-non-fatal.rs +++ b/src/test/compile-fail/attempted-access-non-fatal.rs @@ -11,6 +11,6 @@ // Check that bogus field access is non-fatal fn main() { let x = 0; - let _ = x.foo; //~ ERROR attempted access of field - let _ = x.bar; //~ ERROR attempted access of field + let _ = x.foo; //~ no field `foo` on type `{integer}` + let _ = x.bar; //~ no field `bar` on type `{integer}` } diff --git a/src/test/compile-fail/attr-on-generic-formals-are-visited.rs b/src/test/compile-fail/attr-on-generic-formals-are-visited.rs new file mode 100644 index 0000000000..c902cfdd75 --- /dev/null +++ b/src/test/compile-fail/attr-on-generic-formals-are-visited.rs @@ -0,0 +1,75 @@ +// Copyright 2016 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +// This test ensures that attributes on formals in generic parameter +// lists are included when we are checking for unstable attributes. +// +// Note that feature(generic_param_attrs) *is* enabled here. We are +// checking feature-gating of the attributes themselves, not the +// capability to parse such attributes in that context. + +#![feature(generic_param_attrs)] +#![allow(dead_code)] + +struct StLt<#[lt_struct] 'a>(&'a u32); +//~^ ERROR The attribute `lt_struct` is currently unknown to the compiler +struct StTy<#[ty_struct] I>(I); +//~^ ERROR The attribute `ty_struct` is currently unknown to the compiler + +enum EnLt<#[lt_enum] 'b> { A(&'b u32), B } +//~^ ERROR The attribute `lt_enum` is currently unknown to the compiler +enum EnTy<#[ty_enum] J> { A(J), B } +//~^ ERROR The attribute `ty_enum` is currently unknown to the compiler + +trait TrLt<#[lt_trait] 'c> { fn foo(&self, _: &'c [u32]) -> &'c u32; } +//~^ ERROR The attribute `lt_trait` is currently unknown to the compiler +trait TrTy<#[ty_trait] K> { fn foo(&self, _: K); } +//~^ ERROR The attribute `ty_trait` is currently unknown to the compiler + +type TyLt<#[lt_type] 'd> = &'d u32; +//~^ ERROR The attribute `lt_type` is currently unknown to the compiler +type TyTy<#[ty_type] L> = (L, ); +//~^ ERROR The attribute `ty_type` is currently unknown to the compiler + +impl<#[lt_inherent] 'e> StLt<'e> { } +//~^ ERROR The attribute `lt_inherent` is currently unknown to the compiler +impl<#[ty_inherent] M> StTy { } +//~^ ERROR The attribute `ty_inherent` is currently unknown to the compiler + +impl<#[lt_impl_for] 'f> TrLt<'f> for StLt<'f> { + //~^ ERROR The attribute `lt_impl_for` is currently unknown to the compiler + fn foo(&self, _: &'f [u32]) -> &'f u32 { loop { } } +} +impl<#[ty_impl_for] N> TrTy for StTy { + //~^ ERROR The attribute `ty_impl_for` is currently unknown to the compiler + fn foo(&self, _: N) { } +} + +fn f_lt<#[lt_fn] 'g>(_: &'g [u32]) -> &'g u32 { loop { } } +//~^ ERROR The attribute `lt_fn` is currently unknown to the compiler +fn f_ty<#[ty_fn] O>(_: O) { } +//~^ ERROR The attribute `ty_fn` is currently unknown to the compiler + +impl StTy { + fn m_lt<#[lt_meth] 'h>(_: &'h [u32]) -> &'h u32 { loop { } } + //~^ ERROR The attribute `lt_meth` is currently unknown to the compiler + fn m_ty<#[ty_meth] P>(_: P) { } + //~^ ERROR The attribute `ty_meth` is currently unknown to the compiler +} + +fn hof_lt(_: Q) + where Q: for <#[lt_hof] 'i> Fn(&'i [u32]) -> &'i u32 + //~^ ERROR The attribute `lt_hof` is currently unknown to the compiler +{ +} + +fn main() { + +} diff --git a/src/test/compile-fail/attr-on-generic-formals-wo-feature-gate.rs b/src/test/compile-fail/attr-on-generic-formals-wo-feature-gate.rs new file mode 100644 index 0000000000..944802f450 --- /dev/null +++ b/src/test/compile-fail/attr-on-generic-formals-wo-feature-gate.rs @@ -0,0 +1,76 @@ +// Copyright 2016 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +// This test ensures that attributes on formals in generic parameter +// lists are rejected if feature(generic_param_attrs) is not enabled. +// +// (We are prefixing all tested features with `rustc_`, to ensure that +// the attributes themselves won't be rejected by the compiler when +// using `rustc_attrs` feature. There is a separate compile-fail/ test +// ensuring that the attribute feature-gating works in this context.) + +#![feature(rustc_attrs)] +#![allow(dead_code)] + +struct StLt<#[rustc_lt_struct] 'a>(&'a u32); +//~^ ERROR attributes on lifetime bindings are experimental (see issue #34761) +struct StTy<#[rustc_ty_struct] I>(I); +//~^ ERROR attributes on type parameter bindings are experimental (see issue #34761) + +enum EnLt<#[rustc_lt_enum] 'b> { A(&'b u32), B } +//~^ ERROR attributes on lifetime bindings are experimental (see issue #34761) +enum EnTy<#[rustc_ty_enum] J> { A(J), B } +//~^ ERROR attributes on type parameter bindings are experimental (see issue #34761) + +trait TrLt<#[rustc_lt_trait] 'c> { fn foo(&self, _: &'c [u32]) -> &'c u32; } +//~^ ERROR attributes on lifetime bindings are experimental (see issue #34761) +trait TrTy<#[rustc_ty_trait] K> { fn foo(&self, _: K); } +//~^ ERROR attributes on type parameter bindings are experimental (see issue #34761) + +type TyLt<#[rustc_lt_type] 'd> = &'d u32; +//~^ ERROR attributes on lifetime bindings are experimental (see issue #34761) +type TyTy<#[rustc_ty_type] L> = (L, ); +//~^ ERROR attributes on type parameter bindings are experimental (see issue #34761) + +impl<#[rustc_lt_inherent] 'e> StLt<'e> { } +//~^ ERROR attributes on lifetime bindings are experimental (see issue #34761) +impl<#[rustc_ty_inherent] M> StTy { } +//~^ ERROR attributes on type parameter bindings are experimental (see issue #34761) + +impl<#[rustc_lt_impl_for] 'f> TrLt<'f> for StLt<'f> { + //~^ ERROR attributes on lifetime bindings are experimental (see issue #34761) + fn foo(&self, _: &'f [u32]) -> &'f u32 { loop { } } +} +impl<#[rustc_ty_impl_for] N> TrTy for StTy { + //~^ ERROR attributes on type parameter bindings are experimental (see issue #34761) + fn foo(&self, _: N) { } +} + +fn f_lt<#[rustc_lt_fn] 'g>(_: &'g [u32]) -> &'g u32 { loop { } } +//~^ ERROR attributes on lifetime bindings are experimental (see issue #34761) +fn f_ty<#[rustc_ty_fn] O>(_: O) { } +//~^ ERROR attributes on type parameter bindings are experimental (see issue #34761) + +impl StTy { + fn m_lt<#[rustc_lt_meth] 'h>(_: &'h [u32]) -> &'h u32 { loop { } } + //~^ ERROR attributes on lifetime bindings are experimental (see issue #34761) + fn m_ty<#[rustc_ty_meth] P>(_: P) { } + //~^ ERROR attributes on type parameter bindings are experimental (see issue #34761) +} + +fn hof_lt(_: Q) + where Q: for <#[rustc_lt_hof] 'i> Fn(&'i [u32]) -> &'i u32 + //~^ ERROR attributes on lifetime bindings are experimental (see issue #34761) +{ +} + +fn main() { + +} diff --git a/src/test/compile-fail/attrs-with-no-formal-in-generics-1.rs b/src/test/compile-fail/attrs-with-no-formal-in-generics-1.rs new file mode 100644 index 0000000000..53e287cda2 --- /dev/null +++ b/src/test/compile-fail/attrs-with-no-formal-in-generics-1.rs @@ -0,0 +1,26 @@ +// Copyright 2016 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +// This test checks variations on `<#[attr] 'a, #[oops]>`, where +// `#[oops]` is left dangling (that is, it is unattached, with no +// formal binding following it). + +#![feature(generic_param_attrs, rustc_attrs)] +#![allow(dead_code)] + +struct RefIntPair<'a, 'b>(&'a u32, &'b u32); + +impl<#[rustc_1] 'a, 'b, #[oops]> RefIntPair<'a, 'b> { + //~^ ERROR trailing attribute after lifetime parameters +} + +fn main() { + +} diff --git a/src/test/compile-fail/attrs-with-no-formal-in-generics-2.rs b/src/test/compile-fail/attrs-with-no-formal-in-generics-2.rs new file mode 100644 index 0000000000..a38a7bfb93 --- /dev/null +++ b/src/test/compile-fail/attrs-with-no-formal-in-generics-2.rs @@ -0,0 +1,26 @@ +// Copyright 2016 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +// This test checks variations on `<#[attr] 'a, #[oops]>`, where +// `#[oops]` is left dangling (that is, it is unattached, with no +// formal binding following it). + +#![feature(generic_param_attrs, rustc_attrs)] +#![allow(dead_code)] + +struct RefAny<'a, T>(&'a T); + +impl<#[rustc_1] 'a, #[rustc_2] T, #[oops]> RefAny<'a, T> { + //~^ ERROR expected identifier, found `>` +} + +fn main() { + +} diff --git a/src/test/compile-fail/attrs-with-no-formal-in-generics-3.rs b/src/test/compile-fail/attrs-with-no-formal-in-generics-3.rs new file mode 100644 index 0000000000..e7d5b94d24 --- /dev/null +++ b/src/test/compile-fail/attrs-with-no-formal-in-generics-3.rs @@ -0,0 +1,26 @@ +// Copyright 2016 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +// This test checks variations on `<#[attr] 'a, #[oops]>`, where +// `#[oops]` is left dangling (that is, it is unattached, with no +// formal binding following it). + +struct RefIntPair<'a, 'b>(&'a u32, &'b u32); + +fn hof_lt(_: Q) + where Q: for <#[rustc_1] 'a, 'b, #[oops]> Fn(RefIntPair<'a,'b>) -> &'b u32 + //~^ ERROR trailing attribute after lifetime parameters +{ + +} + +fn main() { + +} diff --git a/src/test/compile-fail/auto-ref-slice-plus-ref.rs b/src/test/compile-fail/auto-ref-slice-plus-ref.rs index f0f0bdfb38..324e925964 100644 --- a/src/test/compile-fail/auto-ref-slice-plus-ref.rs +++ b/src/test/compile-fail/auto-ref-slice-plus-ref.rs @@ -14,7 +14,7 @@ fn main() { // Testing that method lookup does not automatically borrow // vectors to slices then automatically create a self reference. - let mut a = vec!(0); + let mut a = vec![0]; a.test_mut(); //~ ERROR no method named `test_mut` found a.test(); //~ ERROR no method named `test` found diff --git a/src/test/compile-fail/auxiliary/define_macro.rs b/src/test/compile-fail/auxiliary/define_macro.rs new file mode 100644 index 0000000000..6b6b14a896 --- /dev/null +++ b/src/test/compile-fail/auxiliary/define_macro.rs @@ -0,0 +1,16 @@ +// Copyright 2016 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +#[macro_export] +macro_rules! define_macro { + ($i:ident) => { + macro_rules! $i { () => {} } + } +} diff --git a/src/test/compile-fail/auxiliary/import_crate_var.rs b/src/test/compile-fail/auxiliary/import_crate_var.rs new file mode 100644 index 0000000000..1dfc7a128a --- /dev/null +++ b/src/test/compile-fail/auxiliary/import_crate_var.rs @@ -0,0 +1,12 @@ +// Copyright 2016 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +#[macro_export] +macro_rules! m { () => { use $crate; } } diff --git a/src/test/compile-fail/auxiliary/namespace-mix-new.rs b/src/test/compile-fail/auxiliary/namespace-mix-new.rs new file mode 100644 index 0000000000..88e8b0d56f --- /dev/null +++ b/src/test/compile-fail/auxiliary/namespace-mix-new.rs @@ -0,0 +1,78 @@ +// Copyright 2016 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +#![feature(item_like_imports, relaxed_adts)] + +pub mod c { + pub struct S {} + pub struct TS(); + pub struct US; + pub enum E { + V {}, + TV(), + UV, + } + + pub struct Item; +} + +pub mod xm1 { + pub use ::c::*; + pub type S = ::c::Item; +} +pub mod xm2 { + pub use ::c::*; + pub const S: ::c::Item = ::c::Item; +} + +pub mod xm3 { + pub use ::c::*; + pub type TS = ::c::Item; +} +pub mod xm4 { + pub use ::c::*; + pub const TS: ::c::Item = ::c::Item; +} + +pub mod xm5 { + pub use ::c::*; + pub type US = ::c::Item; +} +pub mod xm6 { + pub use ::c::*; + pub const US: ::c::Item = ::c::Item; +} + +pub mod xm7 { + pub use ::c::E::*; + pub type V = ::c::Item; +} +pub mod xm8 { + pub use ::c::E::*; + pub const V: ::c::Item = ::c::Item; +} + +pub mod xm9 { + pub use ::c::E::*; + pub type TV = ::c::Item; +} +pub mod xmA { + pub use ::c::E::*; + pub const TV: ::c::Item = ::c::Item; +} + +pub mod xmB { + pub use ::c::E::*; + pub type UV = ::c::Item; +} +pub mod xmC { + pub use ::c::E::*; + pub const UV: ::c::Item = ::c::Item; +} diff --git a/src/test/compile-fail/auxiliary/namespace-mix-old.rs b/src/test/compile-fail/auxiliary/namespace-mix-old.rs new file mode 100644 index 0000000000..7bbba7163b --- /dev/null +++ b/src/test/compile-fail/auxiliary/namespace-mix-old.rs @@ -0,0 +1,85 @@ +// Copyright 2016 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +// FIXME: Remove when `item_like_imports` is stabilized. + +#![feature(relaxed_adts)] + +pub mod c { + pub struct S {} + pub struct TS(); + pub struct US; + pub enum E { + V {}, + TV(), + UV, + } + + pub struct Item; +} + +pub mod proxy { + pub use c::*; + pub use c::E::*; +} + +pub mod xm1 { + pub use ::proxy::*; + pub type S = ::c::Item; +} +pub mod xm2 { + pub use ::proxy::*; + pub const S: ::c::Item = ::c::Item; +} + +pub mod xm3 { + pub use ::proxy::*; + pub type TS = ::c::Item; +} +pub mod xm4 { + pub use ::proxy::*; + pub const TS: ::c::Item = ::c::Item; +} + +pub mod xm5 { + pub use ::proxy::*; + pub type US = ::c::Item; +} +pub mod xm6 { + pub use ::proxy::*; + pub const US: ::c::Item = ::c::Item; +} + +pub mod xm7 { + pub use ::proxy::*; + pub type V = ::c::Item; +} +pub mod xm8 { + pub use ::proxy::*; + pub const V: ::c::Item = ::c::Item; +} + +pub mod xm9 { + pub use ::proxy::*; + pub type TV = ::c::Item; +} +pub mod xmA { + pub use ::proxy::*; + pub const TV: ::c::Item = ::c::Item; +} + +pub mod xmB { + pub use ::proxy::*; + pub type UV = ::c::Item; +} +pub mod xmC { + pub use ::proxy::*; + pub const UV: ::c::Item = ::c::Item; +} diff --git a/src/test/compile-fail/blind-item-block-middle.rs b/src/test/compile-fail/blind-item-block-middle.rs index f57727b773..0db7eaf0ca 100644 --- a/src/test/compile-fail/blind-item-block-middle.rs +++ b/src/test/compile-fail/blind-item-block-middle.rs @@ -12,6 +12,6 @@ mod foo { pub struct bar; } fn main() { let bar = 5; - //~^ ERROR let bindings cannot shadow structs + //~^ ERROR let bindings cannot shadow unit structs use foo::bar; } diff --git a/src/test/compile-fail/borrowck/borrowck-assign-comp-idx.rs b/src/test/compile-fail/borrowck/borrowck-assign-comp-idx.rs index b18df7f3db..1e665a12a1 100644 --- a/src/test/compile-fail/borrowck/borrowck-assign-comp-idx.rs +++ b/src/test/compile-fail/borrowck/borrowck-assign-comp-idx.rs @@ -14,7 +14,7 @@ struct Point { } fn a() { - let mut p = vec!(1); + let mut p = vec![1]; // Create an immutable pointer into p's contents: let q: &isize = &p[0]; @@ -30,7 +30,7 @@ fn b() { // here we alias the mutable vector into an imm slice and try to // modify the original: - let mut p = vec!(1); + let mut p = vec![1]; borrow( &p, @@ -40,7 +40,7 @@ fn b() { fn c() { // Legal because the scope of the borrow does not include the // modification: - let mut p = vec!(1); + let mut p = vec![1]; borrow(&p, ||{}); p[0] = 5; } diff --git a/src/test/compile-fail/borrowck/borrowck-borrowed-uniq-rvalue-2.rs b/src/test/compile-fail/borrowck/borrowck-borrowed-uniq-rvalue-2.rs index 7b811f581c..9178aadeee 100644 --- a/src/test/compile-fail/borrowck/borrowck-borrowed-uniq-rvalue-2.rs +++ b/src/test/compile-fail/borrowck/borrowck-borrowed-uniq-rvalue-2.rs @@ -29,6 +29,6 @@ fn defer<'r>(x: &'r [&'r str]) -> defer<'r> { } fn main() { - let x = defer(&vec!("Goodbye", "world!")); + let x = defer(&vec!["Goodbye", "world!"]); x.x[0]; } diff --git a/src/test/compile-fail/borrowck/borrowck-loan-vec-content.rs b/src/test/compile-fail/borrowck/borrowck-loan-vec-content.rs index 21d9dea77b..c5de95f8fc 100644 --- a/src/test/compile-fail/borrowck/borrowck-loan-vec-content.rs +++ b/src/test/compile-fail/borrowck/borrowck-loan-vec-content.rs @@ -17,12 +17,12 @@ fn takes_imm_elt(_v: &isize, f: F) where F: FnOnce() { } fn has_mut_vec_and_does_not_try_to_change_it() { - let mut v: Vec = vec!(1, 2, 3); + let mut v: Vec = vec![1, 2, 3]; takes_imm_elt(&v[0], || {}) } fn has_mut_vec_but_tries_to_change_it() { - let mut v: Vec = vec!(1, 2, 3); + let mut v: Vec = vec![1, 2, 3]; takes_imm_elt( &v[0], || { //~ ERROR cannot borrow `v` as mutable diff --git a/src/test/compile-fail/borrowck/borrowck-move-out-of-overloaded-auto-deref.rs b/src/test/compile-fail/borrowck/borrowck-move-out-of-overloaded-auto-deref.rs index 27cef1f3c6..bf4c747413 100644 --- a/src/test/compile-fail/borrowck/borrowck-move-out-of-overloaded-auto-deref.rs +++ b/src/test/compile-fail/borrowck/borrowck-move-out-of-overloaded-auto-deref.rs @@ -11,6 +11,6 @@ use std::rc::Rc; pub fn main() { - let _x = Rc::new(vec!(1, 2)).into_iter(); + let _x = Rc::new(vec![1, 2]).into_iter(); //~^ ERROR cannot move out of borrowed content } diff --git a/src/test/compile-fail/borrowck/borrowck-move-out-of-vec-tail.rs b/src/test/compile-fail/borrowck/borrowck-move-out-of-vec-tail.rs index 51e00a0ad2..311208f07b 100644 --- a/src/test/compile-fail/borrowck/borrowck-move-out-of-vec-tail.rs +++ b/src/test/compile-fail/borrowck/borrowck-move-out-of-vec-tail.rs @@ -18,11 +18,11 @@ struct Foo { } pub fn main() { - let x = vec!( + let x = vec![ Foo { string: "foo".to_string() }, Foo { string: "bar".to_string() }, Foo { string: "baz".to_string() } - ); + ]; let x: &[Foo] = &x; match *x { [_, ref tail..] => { diff --git a/src/test/compile-fail/borrowck/borrowck-mut-slice-of-imm-vec.rs b/src/test/compile-fail/borrowck/borrowck-mut-slice-of-imm-vec.rs index 9341758afd..4e0304e20c 100644 --- a/src/test/compile-fail/borrowck/borrowck-mut-slice-of-imm-vec.rs +++ b/src/test/compile-fail/borrowck/borrowck-mut-slice-of-imm-vec.rs @@ -13,6 +13,6 @@ fn write(v: &mut [isize]) { } fn main() { - let v = vec!(1, 2, 3); + let v = vec![1, 2, 3]; write(&mut v); //~ ERROR cannot borrow } diff --git a/src/test/compile-fail/borrowck/borrowck-overloaded-index-move-from-vec.rs b/src/test/compile-fail/borrowck/borrowck-overloaded-index-move-from-vec.rs index 1b62d9c326..df72c2b0af 100644 --- a/src/test/compile-fail/borrowck/borrowck-overloaded-index-move-from-vec.rs +++ b/src/test/compile-fail/borrowck/borrowck-overloaded-index-move-from-vec.rs @@ -25,7 +25,7 @@ impl Index for MyVec { } fn main() { - let v = MyVec::> { data: vec!(box 1, box 2, box 3) }; + let v = MyVec::> { data: vec![box 1, box 2, box 3] }; let good = &v[0]; // Shouldn't fail here let bad = v[0]; //~^ ERROR cannot move out of indexed content diff --git a/src/test/compile-fail/borrowck/borrowck-use-uninitialized-in-cast.rs b/src/test/compile-fail/borrowck/borrowck-use-uninitialized-in-cast.rs index a3d5af80b5..3f429bbd4b 100644 --- a/src/test/compile-fail/borrowck/borrowck-use-uninitialized-in-cast.rs +++ b/src/test/compile-fail/borrowck/borrowck-use-uninitialized-in-cast.rs @@ -12,8 +12,6 @@ // 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/borrowck/borrowck-vec-pattern-element-loan.rs b/src/test/compile-fail/borrowck/borrowck-vec-pattern-element-loan.rs index 63e80b90ac..eb5d69d49b 100644 --- a/src/test/compile-fail/borrowck/borrowck-vec-pattern-element-loan.rs +++ b/src/test/compile-fail/borrowck/borrowck-vec-pattern-element-loan.rs @@ -12,7 +12,7 @@ #![feature(slice_patterns)] fn a<'a>() -> &'a [isize] { - let vec = vec!(1, 2, 3, 4); + let vec = vec![1, 2, 3, 4]; let vec: &[isize] = &vec; //~ ERROR does not live long enough let tail = match vec { &[_, ref tail..] => tail, @@ -22,7 +22,7 @@ fn a<'a>() -> &'a [isize] { } fn b<'a>() -> &'a [isize] { - let vec = vec!(1, 2, 3, 4); + let vec = vec![1, 2, 3, 4]; let vec: &[isize] = &vec; //~ ERROR does not live long enough let init = match vec { &[ref init.., _] => init, @@ -32,7 +32,7 @@ fn b<'a>() -> &'a [isize] { } fn c<'a>() -> &'a [isize] { - let vec = vec!(1, 2, 3, 4); + let vec = vec![1, 2, 3, 4]; let vec: &[isize] = &vec; //~ ERROR does not live long enough let slice = match vec { &[_, ref slice.., _] => slice, diff --git a/src/test/compile-fail/borrowck/borrowck-vec-pattern-loan-from-mut.rs b/src/test/compile-fail/borrowck/borrowck-vec-pattern-loan-from-mut.rs index 9dfd4d7792..505c8c6d53 100644 --- a/src/test/compile-fail/borrowck/borrowck-vec-pattern-loan-from-mut.rs +++ b/src/test/compile-fail/borrowck/borrowck-vec-pattern-loan-from-mut.rs @@ -11,7 +11,7 @@ #![feature(slice_patterns)] fn a() { - let mut v = vec!(1, 2, 3); + let mut v = vec![1, 2, 3]; let vb: &mut [isize] = &mut v; match vb { &mut [_a, ref tail..] => { diff --git a/src/test/compile-fail/borrowck/borrowck-vec-pattern-nesting.rs b/src/test/compile-fail/borrowck/borrowck-vec-pattern-nesting.rs index ae001e4e34..d26364efdb 100644 --- a/src/test/compile-fail/borrowck/borrowck-vec-pattern-nesting.rs +++ b/src/test/compile-fail/borrowck/borrowck-vec-pattern-nesting.rs @@ -25,7 +25,7 @@ fn a() { } fn b() { - let mut vec = vec!(box 1, box 2, box 3); + let mut vec = vec![box 1, box 2, box 3]; let vec: &mut [Box] = &mut vec; match vec { &mut [ref _b..] => { @@ -37,7 +37,7 @@ fn b() { } fn c() { - let mut vec = vec!(box 1, box 2, box 3); + let mut vec = vec![box 1, box 2, box 3]; let vec: &mut [Box] = &mut vec; match vec { &mut [_a, //~ ERROR cannot move out @@ -59,7 +59,7 @@ fn c() { } fn d() { - let mut vec = vec!(box 1, box 2, box 3); + let mut vec = vec![box 1, box 2, box 3]; let vec: &mut [Box] = &mut vec; match vec { &mut [ //~ ERROR cannot move out @@ -73,7 +73,7 @@ fn d() { } fn e() { - let mut vec = vec!(box 1, box 2, box 3); + let mut vec = vec![box 1, box 2, box 3]; let vec: &mut [Box] = &mut vec; match vec { &mut [_a, _b, _c] => {} //~ ERROR cannot move out diff --git a/src/test/compile-fail/borrowck/borrowck-vec-pattern-tail-element-loan.rs b/src/test/compile-fail/borrowck/borrowck-vec-pattern-tail-element-loan.rs index a849e4e2fa..cd8f3ebefe 100644 --- a/src/test/compile-fail/borrowck/borrowck-vec-pattern-tail-element-loan.rs +++ b/src/test/compile-fail/borrowck/borrowck-vec-pattern-tail-element-loan.rs @@ -11,7 +11,7 @@ #![feature(slice_patterns)] fn a<'a>() -> &'a isize { - let vec = vec!(1, 2, 3, 4); + let vec = vec![1, 2, 3, 4]; let vec: &[isize] = &vec; //~ ERROR `vec` does not live long enough let tail = match vec { &[_a, ref tail..] => &tail[0], diff --git a/src/test/compile-fail/cast-rfc0401.rs b/src/test/compile-fail/cast-rfc0401.rs index b6e81504a9..0c373057c7 100644 --- a/src/test/compile-fail/cast-rfc0401.rs +++ b/src/test/compile-fail/cast-rfc0401.rs @@ -92,7 +92,7 @@ fn main() let _ = v as *const [u8]; //~ ERROR cannot cast let _ = fat_v as *const Foo; //~^ ERROR the trait bound `[u8]: std::marker::Sized` is not satisfied - //~| NOTE trait `[u8]: std::marker::Sized` not satisfied + //~| NOTE the trait `std::marker::Sized` is not implemented for `[u8]` //~| NOTE `[u8]` does not have a constant size known at compile-time //~| NOTE required for the cast to the object type `Foo` let _ = foo as *const str; //~ ERROR casting @@ -107,12 +107,12 @@ fn main() let a : *const str = "hello"; let _ = a as *const Foo; //~^ ERROR the trait bound `str: std::marker::Sized` is not satisfied - //~| NOTE trait `str: std::marker::Sized` not satisfied + //~| NOTE the trait `std::marker::Sized` is not implemented for `str` //~| NOTE `str` does not have a constant size known at compile-time //~| NOTE required for the cast to the object type `Foo` // check no error cascade - let _ = main.f as *const u32; //~ ERROR attempted access of field + let _ = main.f as *const u32; //~ no field `f` on type `fn() {main}` let cf: *const Foo = &0; let _ = cf as *const [u16]; diff --git a/src/test/compile-fail/coherence-cow.rs b/src/test/compile-fail/coherence-cow.rs index 6a2d1bac49..86ae5b44d9 100644 --- a/src/test/compile-fail/coherence-cow.rs +++ b/src/test/compile-fail/coherence-cow.rs @@ -12,8 +12,6 @@ // aux-build:coherence_lib.rs -// pretty-expanded FIXME #23616 - // Test that the `Pair` type reports an error if it contains type // parameters, even when they are covered by local types. This test // was originally intended to test the opposite, but the rules changed diff --git a/src/test/compile-fail/coherence-vec-local-2.rs b/src/test/compile-fail/coherence-vec-local-2.rs index 5f0b56af2c..196c2f4ee3 100644 --- a/src/test/compile-fail/coherence-vec-local-2.rs +++ b/src/test/compile-fail/coherence-vec-local-2.rs @@ -13,8 +13,6 @@ // aux-build:coherence_lib.rs -// pretty-expanded FIXME #23616 - extern crate coherence_lib as lib; use lib::Remote; diff --git a/src/test/compile-fail/coherence-vec-local.rs b/src/test/compile-fail/coherence-vec-local.rs index c354caac2b..49822dcfcb 100644 --- a/src/test/compile-fail/coherence-vec-local.rs +++ b/src/test/compile-fail/coherence-vec-local.rs @@ -13,8 +13,6 @@ // aux-build:coherence_lib.rs -// pretty-expanded FIXME #23616 - extern crate coherence_lib as lib; use lib::Remote; diff --git a/src/test/compile-fail/const-eval-overflow-2.rs b/src/test/compile-fail/const-eval-overflow-2.rs index 264f02588a..9b045ed1d0 100644 --- a/src/test/compile-fail/const-eval-overflow-2.rs +++ b/src/test/compile-fail/const-eval-overflow-2.rs @@ -21,10 +21,6 @@ const NEG_128: i8 = -128; const NEG_NEG_128: i8 = -NEG_128; //~^ ERROR constant evaluation error //~| attempt to negate with overflow -//~| ERROR constant evaluation error -//~| attempt to negate with overflow -//~| ERROR constant evaluation error -//~| attempt to negate with overflow fn main() { match -128i8 { diff --git a/src/test/compile-fail/const-pattern-not-const-evaluable.rs b/src/test/compile-fail/const-pattern-not-const-evaluable.rs index d68d63683a..b40aa2a8e2 100644 --- a/src/test/compile-fail/const-pattern-not-const-evaluable.rs +++ b/src/test/compile-fail/const-pattern-not-const-evaluable.rs @@ -25,13 +25,11 @@ const fn foo() -> Cake { Marmor //~^ ERROR: constant evaluation error [E0080] //~| unimplemented constant expression: enum variants - //~^^^ ERROR: constant evaluation error [E0080] - //~| unimplemented constant expression: enum variants } const WORKS: Cake = Marmor; -const GOO: Cake = foo(); //~ NOTE for expression here +const GOO: Cake = foo(); fn main() { match BlackForest { diff --git a/src/test/compile-fail/const-unsized.rs b/src/test/compile-fail/const-unsized.rs index a73164b957..226b567c54 100644 --- a/src/test/compile-fail/const-unsized.rs +++ b/src/test/compile-fail/const-unsized.rs @@ -12,25 +12,25 @@ use std::fmt::Debug; const CONST_0: Debug+Sync = *(&0 as &(Debug+Sync)); //~^ ERROR `std::fmt::Debug + Sync + 'static: std::marker::Sized` is not satisfied -//~| NOTE `std::fmt::Debug + Sync + 'static: std::marker::Sized` not satisfied +//~| NOTE the trait `std::marker::Sized` is not implemented for `std::fmt::Debug + Sync + 'static` //~| NOTE does not have a constant size known at compile-time //~| NOTE constant expressions must have a statically known size const CONST_FOO: str = *"foo"; //~^ ERROR `str: std::marker::Sized` is not satisfied -//~| NOTE `str: std::marker::Sized` not satisfied +//~| NOTE the trait `std::marker::Sized` is not implemented for `str` //~| NOTE does not have a constant size known at compile-time //~| NOTE constant expressions must have a statically known size static STATIC_1: Debug+Sync = *(&1 as &(Debug+Sync)); //~^ ERROR `std::fmt::Debug + Sync + 'static: std::marker::Sized` is not satisfied -//~| NOTE `std::fmt::Debug + Sync + 'static: std::marker::Sized` not satisfied +//~| NOTE the trait `std::marker::Sized` is not implemented for `std::fmt::Debug + Sync + 'static` //~| NOTE does not have a constant size known at compile-time //~| NOTE constant expressions must have a statically known size static STATIC_BAR: str = *"bar"; //~^ ERROR `str: std::marker::Sized` is not satisfied -//~| NOTE `str: std::marker::Sized` not satisfied +//~| NOTE the trait `std::marker::Sized` is not implemented for `str` //~| NOTE does not have a constant size known at compile-time //~| NOTE constant expressions must have a statically known size diff --git a/src/test/compile-fail/dep-graph-type-alias.rs b/src/test/compile-fail/dep-graph-type-alias.rs new file mode 100644 index 0000000000..80cc9e71c7 --- /dev/null +++ b/src/test/compile-fail/dep-graph-type-alias.rs @@ -0,0 +1,56 @@ +// Copyright 2016 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + + +// Test that changing what a `type` points to does not go unnoticed. + +// compile-flags: -Z query-dep-graph + +#![feature(rustc_attrs)] +#![allow(dead_code)] +#![allow(unused_variables)] + +fn main() { } + + +#[rustc_if_this_changed] +type TypeAlias = u32; + +#[rustc_then_this_would_need(ItemSignature)] //~ ERROR OK +struct Struct { + x: TypeAlias, + y: u32 +} + +#[rustc_then_this_would_need(ItemSignature)] //~ ERROR OK +enum Enum { + Variant1(TypeAlias), + Variant2(i32) +} + +#[rustc_then_this_would_need(ItemSignature)] //~ ERROR OK +trait Trait { + fn method(&self, _: TypeAlias); +} + +struct SomeType; + +#[rustc_then_this_would_need(ItemSignature)] //~ ERROR OK +impl SomeType { + fn method(&self, _: TypeAlias) {} +} + +#[rustc_then_this_would_need(ItemSignature)] //~ ERROR OK +type TypeAlias2 = TypeAlias; + +#[rustc_then_this_would_need(ItemSignature)] //~ ERROR OK +fn function(_: TypeAlias) { + +} diff --git a/src/test/compile-fail/derived-errors/issue-30580.rs b/src/test/compile-fail/derived-errors/issue-30580.rs index 88d4aef6d9..553ad0a334 100644 --- a/src/test/compile-fail/derived-errors/issue-30580.rs +++ b/src/test/compile-fail/derived-errors/issue-30580.rs @@ -19,7 +19,7 @@ impl<'a, 'tcx> Pass<'a, 'tcx> pub fn tcx(&self) -> &'a &'tcx () { self.1 } fn lol(&mut self, b: &Foo) { - b.c; //~ ERROR no field with that name was found + b.c; //~ ERROR no field `c` on type `&Foo` self.tcx(); } } diff --git a/src/test/compile-fail/deriving-meta-unknown-trait.rs b/src/test/compile-fail/deriving-meta-unknown-trait.rs index e223499469..596cc1e7d5 100644 --- a/src/test/compile-fail/deriving-meta-unknown-trait.rs +++ b/src/test/compile-fail/deriving-meta-unknown-trait.rs @@ -8,8 +8,10 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. +// ignore-tidy-linelength + #[derive(Eqr)] -//~^ ERROR `#[derive]` for custom traits is not stable enough for use and is subject to change +//~^ ERROR `#[derive]` for custom traits is not stable enough for use. It is deprecated and will be removed in v1.15 (see issue #29644) struct Foo; pub fn main() {} diff --git a/src/test/compile-fail/discrim-overflow-2.rs b/src/test/compile-fail/discrim-overflow-2.rs index 0ff740212e..213683b580 100644 --- a/src/test/compile-fail/discrim-overflow-2.rs +++ b/src/test/compile-fail/discrim-overflow-2.rs @@ -24,7 +24,9 @@ fn f_i8() { enum A { Ok = i8::MAX - 1, Ok2, - OhNo, //~ ERROR enum discriminant overflowed on value after 127i8; set explicitly via OhNo = -128i8 if that is desired outcome + OhNo, //~ ERROR enum discriminant overflowed [E0370] + //~| NOTE overflowed on value after 127i8 + //~| NOTE explicitly set `OhNo = -128i8` if that is desired outcome } } @@ -33,7 +35,9 @@ fn f_u8() { enum A { Ok = u8::MAX - 1, Ok2, - OhNo, //~ ERROR enum discriminant overflowed on value after 255u8; set explicitly via OhNo = 0u8 if that is desired outcome + OhNo, //~ ERROR enum discriminant overflowed [E0370] + //~| NOTE overflowed on value after 255u8 + //~| NOTE explicitly set `OhNo = 0u8` if that is desired outcome } } @@ -42,7 +46,9 @@ fn f_i16() { enum A { Ok = i16::MAX - 1, Ok2, - OhNo, //~ ERROR enum discriminant overflowed + OhNo, //~ ERROR enum discriminant overflowed [E0370] + //~| NOTE overflowed on value after 32767i16 + //~| NOTE explicitly set `OhNo = -32768i16` if that is desired outcome } } @@ -51,7 +57,9 @@ fn f_u16() { enum A { Ok = u16::MAX - 1, Ok2, - OhNo, //~ ERROR enum discriminant overflowed + OhNo, //~ ERROR enum discriminant overflowed [E0370] + //~| NOTE overflowed on value after 65535u16 + //~| NOTE explicitly set `OhNo = 0u16` if that is desired outcome } } @@ -60,7 +68,9 @@ fn f_i32() { enum A { Ok = i32::MAX - 1, Ok2, - OhNo, //~ ERROR enum discriminant overflowed + OhNo, //~ ERROR enum discriminant overflowed [E0370] + //~| NOTE overflowed on value after 2147483647i32 + //~| NOTE explicitly set `OhNo = -2147483648i32` if that is desired outcome } } @@ -69,7 +79,9 @@ fn f_u32() { enum A { Ok = u32::MAX - 1, Ok2, - OhNo, //~ ERROR enum discriminant overflowed + OhNo, //~ ERROR enum discriminant overflowed [E0370] + //~| NOTE overflowed on value after 4294967295u32 + //~| NOTE explicitly set `OhNo = 0u32` if that is desired outcome } } @@ -78,7 +90,9 @@ fn f_i64() { enum A { Ok = i64::MAX - 1, Ok2, - OhNo, //~ ERROR enum discriminant overflowed + OhNo, //~ ERROR enum discriminant overflowed [E0370] + //~| NOTE overflowed on value after 9223372036854775807i64 + //~| NOTE explicitly set `OhNo = -9223372036854775808i64` if that is desired outcome } } @@ -87,7 +101,9 @@ fn f_u64() { enum A { Ok = u64::MAX - 1, Ok2, - OhNo, //~ ERROR enum discriminant overflowed + OhNo, //~ ERROR enum discriminant overflowed [E0370] + //~| NOTE overflowed on value after 18446744073709551615u64 + //~| NOTE explicitly set `OhNo = 0u64` if that is desired outcome } } diff --git a/src/test/compile-fail/discrim-overflow.rs b/src/test/compile-fail/discrim-overflow.rs index 7316e737b6..a3039b8d95 100644 --- a/src/test/compile-fail/discrim-overflow.rs +++ b/src/test/compile-fail/discrim-overflow.rs @@ -22,7 +22,9 @@ fn f_i8() { enum A { Ok = i8::MAX - 1, Ok2, - OhNo, //~ ERROR enum discriminant overflowed on value after 127i8; set explicitly via OhNo = -128i8 if that is desired outcome + OhNo, //~ ERROR enum discriminant overflowed [E0370] + //~| NOTE overflowed on value after 127i8 + //~| NOTE explicitly set `OhNo = -128i8` if that is desired outcome } let x = A::Ok; @@ -33,7 +35,9 @@ fn f_u8() { enum A { Ok = u8::MAX - 1, Ok2, - OhNo, //~ ERROR enum discriminant overflowed on value after 255u8; set explicitly via OhNo = 0u8 if that is desired outcome + OhNo, //~ ERROR enum discriminant overflowed [E0370] + //~| NOTE overflowed on value after 255u8 + //~| NOTE explicitly set `OhNo = 0u8` if that is desired outcome } let x = A::Ok; @@ -44,7 +48,9 @@ fn f_i16() { enum A { Ok = i16::MAX - 1, Ok2, - OhNo, //~ ERROR enum discriminant overflowed + OhNo, //~ ERROR enum discriminant overflowed [E0370] + //~| NOTE overflowed on value after 32767i16 + //~| NOTE explicitly set `OhNo = -32768i16` if that is desired outcome } let x = A::Ok; @@ -55,7 +61,9 @@ fn f_u16() { enum A { Ok = u16::MAX - 1, Ok2, - OhNo, //~ ERROR enum discriminant overflowed + OhNo, //~ ERROR enum discriminant overflowed [E0370] + //~| overflowed on value after 65535u16 + //~| NOTE explicitly set `OhNo = 0u16` if that is desired outcome } let x = A::Ok; @@ -66,7 +74,9 @@ fn f_i32() { enum A { Ok = i32::MAX - 1, Ok2, - OhNo, //~ ERROR enum discriminant overflowed + OhNo, //~ ERROR enum discriminant overflowed [E0370] + //~| overflowed on value after 2147483647i32 + //~| NOTE explicitly set `OhNo = -2147483648i32` if that is desired outcome } let x = A::Ok; @@ -77,7 +87,9 @@ fn f_u32() { enum A { Ok = u32::MAX - 1, Ok2, - OhNo, //~ ERROR enum discriminant overflowed + OhNo, //~ ERROR enum discriminant overflowed [E0370] + //~| overflowed on value after 4294967295u32 + //~| NOTE explicitly set `OhNo = 0u32` if that is desired outcome } let x = A::Ok; @@ -88,7 +100,9 @@ fn f_i64() { enum A { Ok = i64::MAX - 1, Ok2, - OhNo, //~ ERROR enum discriminant overflowed + OhNo, //~ ERROR enum discriminant overflowed [E0370] + //~| overflowed on value after 9223372036854775807i64 + //~| NOTE explicitly set `OhNo = -9223372036854775808i64` if that is desired outcome } let x = A::Ok; @@ -99,7 +113,9 @@ fn f_u64() { enum A { Ok = u64::MAX - 1, Ok2, - OhNo, //~ ERROR enum discriminant overflowed + OhNo, //~ ERROR enum discriminant overflowed [E0370] + //~| overflowed on value after 18446744073709551615u64 + //~| NOTE explicitly set `OhNo = 0u64` if that is desired outcome } let x = A::Ok; diff --git a/src/test/compile-fail/drop-with-active-borrows-2.rs b/src/test/compile-fail/drop-with-active-borrows-2.rs index e6e1364dd2..33e4d3e62c 100644 --- a/src/test/compile-fail/drop-with-active-borrows-2.rs +++ b/src/test/compile-fail/drop-with-active-borrows-2.rs @@ -9,7 +9,7 @@ // except according to those terms. fn read_lines_borrowed<'a>() -> Vec<&'a str> { - let raw_lines: Vec = vec!("foo ".to_string(), " bar".to_string()); + let raw_lines: Vec = vec!["foo ".to_string(), " bar".to_string()]; raw_lines.iter().map(|l| l.trim()).collect() //~^ ERROR `raw_lines` does not live long enough } diff --git a/src/test/compile-fail/empty-comment.rs b/src/test/compile-fail/empty-comment.rs index 5c521a5f30..a5568ff826 100644 --- a/src/test/compile-fail/empty-comment.rs +++ b/src/test/compile-fail/empty-comment.rs @@ -12,6 +12,10 @@ // This could break some internal logic that assumes the length of a doc comment is at least 5, // leading to an ICE. +macro_rules! one_arg_macro { + ($fmt:expr) => (print!(concat!($fmt, "\n"))); +} + fn main() { - println!(/**/); //~ ERROR unexpected end + one_arg_macro!(/**/); //~ ERROR unexpected end } diff --git a/src/test/compile-fail/empty-struct-braces-pat-1.rs b/src/test/compile-fail/empty-struct-braces-pat-1.rs index 74546152ca..e527170e9f 100644 --- a/src/test/compile-fail/empty-struct-braces-pat-1.rs +++ b/src/test/compile-fail/empty-struct-braces-pat-1.rs @@ -32,13 +32,13 @@ fn main() { } match e3 { E::Empty3 => () - //~^ ERROR `E::Empty3` does not name a unit variant, unit struct or a constant + //~^ ERROR expected unit struct/variant or constant, found struct variant `E::Empty3` } match xe1 { XEmpty1 => () // Not an error, `XEmpty1` is interpreted as a new binding } match xe3 { XE::XEmpty3 => () - //~^ ERROR `XE::XEmpty3` does not name a unit variant, unit struct or a constant + //~^ ERROR expected unit struct/variant or constant, found struct variant `XE::XEmpty3` } } diff --git a/src/test/compile-fail/empty-struct-braces-pat-2.rs b/src/test/compile-fail/empty-struct-braces-pat-2.rs index 52481517ce..58e3ca6b3a 100644 --- a/src/test/compile-fail/empty-struct-braces-pat-2.rs +++ b/src/test/compile-fail/empty-struct-braces-pat-2.rs @@ -24,15 +24,15 @@ fn main() { let xe1 = XEmpty1 {}; match e1 { - Empty1() => () //~ ERROR unresolved variant or struct `Empty1` + Empty1() => () //~ ERROR unresolved tuple struct/variant `Empty1` } match xe1 { - XEmpty1() => () //~ ERROR unresolved variant or struct `XEmpty1` + XEmpty1() => () //~ ERROR unresolved tuple struct/variant `XEmpty1` } match e1 { - Empty1(..) => () //~ ERROR unresolved variant or struct `Empty1` + Empty1(..) => () //~ ERROR unresolved tuple struct/variant `Empty1` } match xe1 { - XEmpty1(..) => () //~ ERROR unresolved variant or struct `XEmpty1` + XEmpty1(..) => () //~ ERROR unresolved tuple struct/variant `XEmpty1` } } diff --git a/src/test/compile-fail/empty-struct-braces-pat-3.rs b/src/test/compile-fail/empty-struct-braces-pat-3.rs index cb859fe750..1960eca9f8 100644 --- a/src/test/compile-fail/empty-struct-braces-pat-3.rs +++ b/src/test/compile-fail/empty-struct-braces-pat-3.rs @@ -26,15 +26,19 @@ fn main() { let xe3 = XE::XEmpty3 {}; match e3 { - E::Empty3() => () //~ ERROR `E::Empty3` does not name a tuple variant or a tuple struct + E::Empty3() => () + //~^ ERROR expected tuple struct/variant, found struct variant `E::Empty3` } match xe3 { - XE::XEmpty3() => () //~ ERROR `XE::XEmpty3` does not name a tuple variant or a tuple struct + XE::XEmpty3() => () + //~^ ERROR expected tuple struct/variant, found struct variant `XE::XEmpty3` } match e3 { - E::Empty3(..) => () //~ ERROR `E::Empty3` does not name a tuple variant or a tuple struct + E::Empty3(..) => () + //~^ ERROR expected tuple struct/variant, found struct variant `E::Empty3` } match xe3 { - XE::XEmpty3(..) => () //~ ERROR `XE::XEmpty3` does not name a tuple variant or a tuple + XE::XEmpty3(..) => () + //~^ ERROR expected tuple struct/variant, found struct variant `XE::XEmpty3 } } diff --git a/src/test/compile-fail/empty-struct-tuple-pat.rs b/src/test/compile-fail/empty-struct-tuple-pat.rs index be90e3b26c..f15c126a12 100644 --- a/src/test/compile-fail/empty-struct-tuple-pat.rs +++ b/src/test/compile-fail/empty-struct-tuple-pat.rs @@ -31,17 +31,19 @@ fn main() { let xe5 = XE::XEmpty5(); match e2 { - Empty2 => () //~ ERROR `Empty2` does not name a unit variant, unit struct or a constant + Empty2 => () //~ ERROR match bindings cannot shadow tuple structs } match xe6 { - XEmpty6 => () //~ ERROR `XEmpty6` does not name a unit variant, unit struct or a constant + XEmpty6 => () //~ ERROR match bindings cannot shadow tuple structs } match e4 { - E::Empty4 => () //~ ERROR `E::Empty4` does not name a unit variant, unit struct or a + E::Empty4 => () + //~^ ERROR expected unit struct/variant or constant, found tuple variant `E::Empty4` } match xe5 { - XE::XEmpty5 => (), //~ ERROR `XE::XEmpty5` does not name a unit variant, unit struct or a + XE::XEmpty5 => (), + //~^ ERROR expected unit struct/variant or constant, found tuple variant `XE::XEmpty5` _ => {}, } } diff --git a/src/test/compile-fail/empty-struct-unit-pat-1.rs b/src/test/compile-fail/empty-struct-unit-pat-1.rs deleted file mode 100644 index aec4ad4cad..0000000000 --- a/src/test/compile-fail/empty-struct-unit-pat-1.rs +++ /dev/null @@ -1,51 +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. - -// Can't use unit struct as enum pattern - -// aux-build:empty-struct.rs - -#![feature(relaxed_adts)] - -extern crate empty_struct; -use empty_struct::*; - -struct Empty2; - -enum E { - Empty4 -} - -// remove attribute after warning cycle and promoting warnings to errors -fn main() { - let e2 = Empty2; - let e4 = E::Empty4; - let xe2 = XEmpty2; - let xe4 = XE::XEmpty4; - - match e2 { - Empty2(..) => () //~ ERROR `Empty2` does not name a tuple variant or a tuple struct - //~^ WARNING hard error - } - match xe2 { - XEmpty2(..) => () //~ ERROR `XEmpty2` does not name a tuple variant or a tuple struct - //~^ WARNING hard error - } - - match e4 { - E::Empty4(..) => () //~ ERROR `E::Empty4` does not name a tuple variant or a tuple struct - //~^ WARNING hard error - } - match xe4 { - XE::XEmpty4(..) => (), //~ ERROR `XE::XEmpty4` does not name a tuple variant or a tuple - //~^ WARNING hard error - _ => {}, - } -} diff --git a/src/test/compile-fail/empty-struct-unit-pat-2.rs b/src/test/compile-fail/empty-struct-unit-pat-2.rs deleted file mode 100644 index 6375a7f233..0000000000 --- a/src/test/compile-fail/empty-struct-unit-pat-2.rs +++ /dev/null @@ -1,47 +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. - -// Can't use unit struct as enum pattern - -// aux-build:empty-struct.rs - -#![feature(relaxed_adts)] - -extern crate empty_struct; -use empty_struct::*; - -struct Empty2; - -enum E { - Empty4 -} - -// remove attribute after warning cycle and promoting warnings to errors -fn main() { - let e2 = Empty2; - let e4 = E::Empty4; - let xe2 = XEmpty2; - let xe4 = XE::XEmpty4; - - match e2 { - Empty2() => () //~ ERROR `Empty2` does not name a tuple variant or a tuple struct - } - match xe2 { - XEmpty2() => () //~ ERROR `XEmpty2` does not name a tuple variant or a tuple struct - } - - match e4 { - E::Empty4() => () //~ ERROR `E::Empty4` does not name a tuple variant or a tuple struct - } - match xe4 { - XE::XEmpty4() => (), //~ ERROR `XE::XEmpty4` does not name a tuple variant or a tuple - _ => {}, - } -} diff --git a/src/test/compile-fail/empty-struct-unit-pat.rs b/src/test/compile-fail/empty-struct-unit-pat.rs new file mode 100644 index 0000000000..90f6ae5755 --- /dev/null +++ b/src/test/compile-fail/empty-struct-unit-pat.rs @@ -0,0 +1,61 @@ +// 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. + +// Can't use unit struct as tuple struct pattern + +// aux-build:empty-struct.rs + +#![feature(relaxed_adts)] + +extern crate empty_struct; +use empty_struct::*; + +struct Empty2; + +enum E { + Empty4 +} + +fn main() { + let e2 = Empty2; + let e4 = E::Empty4; + let xe2 = XEmpty2; + let xe4 = XE::XEmpty4; + + match e2 { + Empty2() => () //~ ERROR expected tuple struct/variant, found unit struct `Empty2` + } + match xe2 { + XEmpty2() => () //~ ERROR expected tuple struct/variant, found unit struct `XEmpty2` + } + match e2 { + Empty2(..) => () //~ ERROR expected tuple struct/variant, found unit struct `Empty2` + } + match xe2 { + XEmpty2(..) => () //~ ERROR expected tuple struct/variant, found unit struct `XEmpty2` + } + + match e4 { + E::Empty4() => () //~ ERROR expected tuple struct/variant, found unit variant `E::Empty4` + } + match xe4 { + XE::XEmpty4() => (), + //~^ ERROR expected tuple struct/variant, found unit variant `XE::XEmpty4` + _ => {}, + } + match e4 { + E::Empty4(..) => () //~ ERROR expected tuple struct/variant, found unit variant `E::Empty4` + } + match xe4 { + XE::XEmpty4(..) => (), + //~^ ERROR expected tuple struct/variant, found unit variant `XE::XEmpty4` + _ => {}, + } +} diff --git a/src/test/compile-fail/enum-in-scope.rs b/src/test/compile-fail/enum-in-scope.rs index e89b08a8a0..bc1bd03f2d 100644 --- a/src/test/compile-fail/enum-in-scope.rs +++ b/src/test/compile-fail/enum-in-scope.rs @@ -11,5 +11,5 @@ struct hello(isize); fn main() { - let hello = 0; //~ERROR let bindings cannot shadow structs + let hello = 0; //~ERROR let bindings cannot shadow tuple structs } diff --git a/src/test/compile-fail/enums-are-namespaced-xc.rs b/src/test/compile-fail/enums-are-namespaced-xc.rs index 5315e6c834..02939565f6 100644 --- a/src/test/compile-fail/enums-are-namespaced-xc.rs +++ b/src/test/compile-fail/enums-are-namespaced-xc.rs @@ -14,5 +14,6 @@ extern crate namespaced_enums; fn main() { let _ = namespaced_enums::A; //~ ERROR unresolved name let _ = namespaced_enums::B(10); //~ ERROR unresolved name - let _ = namespaced_enums::C { a: 10 }; //~ ERROR does not name a structure + let _ = namespaced_enums::C { a: 10 }; + //~^ ERROR unresolved struct, variant or union type `namespaced_enums::C` } diff --git a/src/test/compile-fail/enums-pats-not-idents.rs b/src/test/compile-fail/enums-pats-not-idents.rs index c847366a70..03bdbe4e54 100644 --- a/src/test/compile-fail/enums-pats-not-idents.rs +++ b/src/test/compile-fail/enums-pats-not-idents.rs @@ -9,5 +9,5 @@ // except according to those terms. fn main() { - let a(1) = 13; //~ ERROR unresolved variant or struct `a` + let a(1) = 13; //~ ERROR unresolved tuple struct/variant `a` } diff --git a/src/test/compile-fail/extern-crate-visibility.rs b/src/test/compile-fail/extern-crate-visibility.rs index 86aae47214..81e0cb249f 100644 --- a/src/test/compile-fail/extern-crate-visibility.rs +++ b/src/test/compile-fail/extern-crate-visibility.rs @@ -8,9 +8,7 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -#![feature(rustc_attrs)] -#![allow(dead_code)] -#![allow(unused_imports)] +#![allow(unused)] mod foo { extern crate core; @@ -19,11 +17,11 @@ mod foo { // Check that private crates can be used from outside their modules, albeit with warnings use foo::core; //~ WARN extern crate `core` is private //~^ WARN this was previously accepted by the compiler but is being phased out -use foo::core::cell; //~ WARN extern crate `core` is private +use foo::core::cell; //~ ERROR extern crate `core` is private //~^ WARN this was previously accepted by the compiler but is being phased out fn f() { - foo::core::cell::Cell::new(0); //~ WARN extern crate `core` is private + foo::core::cell::Cell::new(0); //~ ERROR extern crate `core` is private //~^ WARN this was previously accepted by the compiler but is being phased out use foo::*; @@ -39,5 +37,4 @@ mod baz { use self::core::cell; // Check that public extern crates are glob imported } -#[rustc_error] -fn main() {} //~ ERROR compilation successful +fn main() {} diff --git a/src/test/compile-fail/pat-tuple-feature-gate.rs b/src/test/compile-fail/feature-gate-field-init-shorthand.rs similarity index 66% rename from src/test/compile-fail/pat-tuple-feature-gate.rs rename to src/test/compile-fail/feature-gate-field-init-shorthand.rs index 55ca05bdef..cd2dae7f46 100644 --- a/src/test/compile-fail/pat-tuple-feature-gate.rs +++ b/src/test/compile-fail/feature-gate-field-init-shorthand.rs @@ -8,10 +8,17 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. +struct Foo { + x: i32, + y: bool, + z: i32 +} + fn main() { - match 0 { - (..) => {} //~ ERROR `..` in tuple patterns is experimental - (pat, ..) => {} //~ ERROR `..` in tuple patterns is experimental - S(pat, ..) => {} //~ ERROR `..` in tuple struct patterns is experimental - } + let (x, y, z) = (1, true, 2); + let _ = Foo { + x, //~ ERROR struct field shorthands are unstable + y: y, + z //~ ERROR struct field shorthands are unstable + }; } diff --git a/src/test/compile-fail/feature-gate-may-dangle.rs b/src/test/compile-fail/feature-gate-may-dangle.rs new file mode 100644 index 0000000000..23f8ead0ca --- /dev/null +++ b/src/test/compile-fail/feature-gate-may-dangle.rs @@ -0,0 +1,20 @@ +// Copyright 2016 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +// Check that `may_dangle` is rejected if `dropck_eyepatch` feature gate is absent. + +#![feature(generic_param_attrs)] + +struct Pt(A); +impl<#[may_dangle] A> Drop for Pt { + //~^ ERROR may_dangle has unstable semantics and may be removed in the future + //~| HELP add #![feature(dropck_eyepatch)] to the crate attributes to enable + fn drop(&mut self) { } +} diff --git a/src/test/compile-fail/feature-gate-no-debug-2.rs b/src/test/compile-fail/feature-gate-no-debug-2.rs new file mode 100644 index 0000000000..b663c136ee --- /dev/null +++ b/src/test/compile-fail/feature-gate-no-debug-2.rs @@ -0,0 +1,15 @@ +// Copyright 2016 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +#![deny(deprecated)] +#![feature(no_debug)] + +#[no_debug] //~ ERROR use of deprecated attribute `no_debug` +fn main() {} diff --git a/src/test/compile-fail/gated-non-ascii-idents.rs b/src/test/compile-fail/gated-non-ascii-idents.rs index f4b9830d57..9e042c3a7d 100644 --- a/src/test/compile-fail/gated-non-ascii-idents.rs +++ b/src/test/compile-fail/gated-non-ascii-idents.rs @@ -8,7 +8,7 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -extern crate bäz; //~ ERROR non-ascii idents +extern crate core as bäz; //~ ERROR non-ascii idents use föö::bar; //~ ERROR non-ascii idents diff --git a/src/test/compile-fail/generic-type-less-params-with-defaults.rs b/src/test/compile-fail/generic-type-less-params-with-defaults.rs index d9ac715fa9..9b1f3e5164 100644 --- a/src/test/compile-fail/generic-type-less-params-with-defaults.rs +++ b/src/test/compile-fail/generic-type-less-params-with-defaults.rs @@ -18,5 +18,5 @@ struct Vec( fn main() { let _: Vec; //~^ ERROR E0243 - //~| NOTE expected at least 1 type arguments, found 0 + //~| NOTE expected at least 1 type argument, found 0 } diff --git a/src/test/compile-fail/if-without-else-result.rs b/src/test/compile-fail/if-without-else-result.rs index e8aa1f70ea..95bcce5a84 100644 --- a/src/test/compile-fail/if-without-else-result.rs +++ b/src/test/compile-fail/if-without-else-result.rs @@ -10,7 +10,7 @@ fn main() { let a = if true { true }; - //~^ ERROR if may be missing an else clause + //~^ ERROR if may be missing an else clause [E0317] //~| expected type `()` //~| found type `bool` //~| expected (), found bool diff --git a/src/test/compile-fail/impl-trait/auto-trait-leak.rs b/src/test/compile-fail/impl-trait/auto-trait-leak.rs index 60ad266e7f..f055d20e13 100644 --- a/src/test/compile-fail/impl-trait/auto-trait-leak.rs +++ b/src/test/compile-fail/impl-trait/auto-trait-leak.rs @@ -26,7 +26,7 @@ fn send(_: T) {} fn main() { send(before()); //~^ ERROR the trait bound `std::rc::Rc>: std::marker::Send` is not satisfied - //~| NOTE trait `std::rc::Rc>: std::marker::Send` not satisfied + //~| NOTE the trait `std::marker::Send` is not implemented for `std::rc::Rc>` //~| NOTE `std::rc::Rc>` cannot be sent between threads safely //~| NOTE required because it appears within the type `[closure //~| NOTE required because it appears within the type `impl std::ops::Fn<(i32,)>` @@ -34,7 +34,7 @@ fn main() { send(after()); //~^ ERROR the trait bound `std::rc::Rc>: std::marker::Send` is not satisfied - //~| NOTE trait `std::rc::Rc>: std::marker::Send` not satisfied + //~| NOTE the trait `std::marker::Send` is not implemented for `std::rc::Rc>` //~| NOTE `std::rc::Rc>` cannot be sent between threads safely //~| NOTE required because it appears within the type `[closure //~| NOTE required because it appears within the type `impl std::ops::Fn<(i32,)>` @@ -54,7 +54,7 @@ fn after() -> impl Fn(i32) { fn cycle1() -> impl Clone { send(cycle2().clone()); //~^ ERROR the trait bound `std::rc::Rc: std::marker::Send` is not satisfied - //~| NOTE trait `std::rc::Rc: std::marker::Send` not satisfied + //~| NOTE the trait `std::marker::Send` is not implemented for `std::rc::Rc` //~| NOTE `std::rc::Rc` cannot be sent between threads safely //~| NOTE required because it appears within the type `impl std::clone::Clone` //~| NOTE required by `send` @@ -65,7 +65,7 @@ fn cycle1() -> impl Clone { fn cycle2() -> impl Clone { send(cycle1().clone()); //~^ ERROR the trait bound `std::rc::Rc>: std::marker::Send` is not satisfied - //~| NOTE trait `std::rc::Rc>: std::marker::Send` not satisfied + //~| NOTE the trait `std::marker::Send` is not implemented for `std::rc::Rc>` //~| NOTE `std::rc::Rc>` cannot be sent between threads safely //~| NOTE required because it appears within the type `impl std::clone::Clone` //~| NOTE required by `send` diff --git a/src/test/compile-fail/import-crate-var.rs b/src/test/compile-fail/import-crate-var.rs new file mode 100644 index 0000000000..9f57394548 --- /dev/null +++ b/src/test/compile-fail/import-crate-var.rs @@ -0,0 +1,21 @@ +// Copyright 2016 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +// aux-build:import_crate_var.rs +// error-pattern: `$crate` may not be imported +// error-pattern: `use $crate;` was erroneously allowed and will become a hard error + +#![feature(rustc_attrs)] + +#[macro_use] extern crate import_crate_var; +m!(); + +#[rustc_error] +fn main() {} diff --git a/src/test/compile-fail/inherent-overlap.rs b/src/test/compile-fail/inherent-overlap.rs index 333a4ee04b..00d4124463 100644 --- a/src/test/compile-fail/inherent-overlap.rs +++ b/src/test/compile-fail/inherent-overlap.rs @@ -11,13 +11,12 @@ // Test that you cannot define items with the same name in overlapping inherent // impl blocks. -#![feature(rustc_attrs)] -#![allow(dead_code)] +#![allow(unused)] struct Foo; impl Foo { - fn id() {} //~ WARN duplicate definitions + fn id() {} //~ ERROR duplicate definitions //~^ WARN previously accepted } @@ -28,7 +27,7 @@ impl Foo { struct Bar(T); impl Bar { - fn bar(&self) {} //~ WARN duplicate definitions + fn bar(&self) {} //~ ERROR duplicate definitions //~^ WARN previously accepted } @@ -39,7 +38,7 @@ impl Bar { struct Baz(T); impl Baz { - fn baz(&self) {} //~ WARN duplicate definitions + fn baz(&self) {} //~ ERROR duplicate definitions //~^ WARN previously accepted } @@ -47,5 +46,4 @@ impl Baz> { fn baz(&self) {} } -#[rustc_error] -fn main() {} //~ ERROR compilation successful +fn main() {} diff --git a/src/test/compile-fail/integral-indexing.rs b/src/test/compile-fail/integral-indexing.rs index 897aca66cb..c8f33c3caf 100644 --- a/src/test/compile-fail/integral-indexing.rs +++ b/src/test/compile-fail/integral-indexing.rs @@ -9,7 +9,7 @@ // except according to those terms. pub fn main() { - let v: Vec = vec!(0, 1, 2, 3, 4, 5); + let v: Vec = vec![0, 1, 2, 3, 4, 5]; let s: String = "abcdef".to_string(); v[3_usize]; v[3]; diff --git a/src/test/compile-fail/issue-10200.rs b/src/test/compile-fail/issue-10200.rs index 9eec8487a5..8c58ef6261 100644 --- a/src/test/compile-fail/issue-10200.rs +++ b/src/test/compile-fail/issue-10200.rs @@ -13,7 +13,7 @@ fn foo(_: usize) -> Foo { Foo(false) } fn main() { match Foo(true) { - foo(x) //~ ERROR expected variant or struct, found function `foo` + foo(x) //~ ERROR expected tuple struct/variant, found function `foo` => () } } diff --git a/src/test/compile-fail/issue-11004.rs b/src/test/compile-fail/issue-11004.rs index 308be46271..0698834242 100644 --- a/src/test/compile-fail/issue-11004.rs +++ b/src/test/compile-fail/issue-11004.rs @@ -14,9 +14,9 @@ struct A { x: i32, y: f64 } #[cfg(not(works))] unsafe fn access(n:*mut A) -> (i32, f64) { - let x : i32 = n.x; //~ ERROR attempted access of field `x` + let x : i32 = n.x; //~ no field `x` on type `*mut A` //~| NOTE `n` is a native pointer; perhaps you need to deref with `(*n).x` - let y : f64 = n.y; //~ ERROR attempted access of field `y` + let y : f64 = n.y; //~ no field `y` on type `*mut A` //~| NOTE `n` is a native pointer; perhaps you need to deref with `(*n).y` (x, y) } diff --git a/src/test/compile-fail/issue-11873.rs b/src/test/compile-fail/issue-11873.rs index 38956944f6..4618851529 100644 --- a/src/test/compile-fail/issue-11873.rs +++ b/src/test/compile-fail/issue-11873.rs @@ -9,7 +9,7 @@ // except according to those terms. fn main() { - let mut v = vec!(1); + let mut v = vec![1]; let mut f = || v.push(2); let _w = v; //~ ERROR: cannot move out of `v` diff --git a/src/test/compile-fail/issue-12612.rs b/src/test/compile-fail/issue-12612.rs index 20943bd0ea..c6f76ca788 100644 --- a/src/test/compile-fail/issue-12612.rs +++ b/src/test/compile-fail/issue-12612.rs @@ -16,7 +16,7 @@ use foo::bar; mod test { use bar::foo; //~ ERROR unresolved import `bar::foo` [E0432] - //~^ Maybe a missing `extern crate bar`? + //~^ Maybe a missing `extern crate bar;`? } fn main() {} diff --git a/src/test/compile-fail/issue-12863.rs b/src/test/compile-fail/issue-12863.rs index 7912410f69..d3432410c5 100644 --- a/src/test/compile-fail/issue-12863.rs +++ b/src/test/compile-fail/issue-12863.rs @@ -12,6 +12,6 @@ mod foo { pub fn bar() {} } fn main() { match () { - foo::bar => {} //~ ERROR expected variant, struct or constant, found function `bar` + foo::bar => {} //~ ERROR expected unit struct/variant or constant, found function `foo::bar` } } diff --git a/src/test/compile-fail/issue-13352.rs b/src/test/compile-fail/issue-13352.rs index 13e677d72b..0c446f5fe4 100644 --- a/src/test/compile-fail/issue-13352.rs +++ b/src/test/compile-fail/issue-13352.rs @@ -8,8 +8,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -// pretty-expanded FIXME #23616 - fn foo(_: Box) {} fn main() { diff --git a/src/test/compile-fail/issue-13446.rs b/src/test/compile-fail/issue-13446.rs index 53d1486288..6ad3ec67b2 100644 --- a/src/test/compile-fail/issue-13446.rs +++ b/src/test/compile-fail/issue-13446.rs @@ -13,6 +13,6 @@ // error-pattern: mismatched types -static VEC: [u32; 256] = vec!(); +static VEC: [u32; 256] = vec![]; fn main() {} diff --git a/src/test/compile-fail/issue-14092.rs b/src/test/compile-fail/issue-14092.rs index dd02fa7ac1..df8707ab82 100644 --- a/src/test/compile-fail/issue-14092.rs +++ b/src/test/compile-fail/issue-14092.rs @@ -10,6 +10,6 @@ fn fn1(0: Box) {} //~^ ERROR E0243 - //~| NOTE expected 1 type arguments, found 0 + //~| NOTE expected 1 type argument, found 0 fn main() {} diff --git a/src/test/compile-fail/issue-14721.rs b/src/test/compile-fail/issue-14721.rs index 92add18f94..58e8e10ee3 100644 --- a/src/test/compile-fail/issue-14721.rs +++ b/src/test/compile-fail/issue-14721.rs @@ -10,6 +10,5 @@ fn main() { let foo = "str"; - println!("{}", foo.desc); //~ ERROR attempted access of field `desc` on type `&str`, - // but no field with that name was found + println!("{}", foo.desc); //~ no field `desc` on type `&str` } diff --git a/src/test/compile-fail/issue-14853.rs b/src/test/compile-fail/issue-14853.rs index c4d8826703..e4da3e4fa4 100644 --- a/src/test/compile-fail/issue-14853.rs +++ b/src/test/compile-fail/issue-14853.rs @@ -20,7 +20,7 @@ struct X { data: u32 } impl Something for X { fn yay(_:Option, thing: &[T]) { - //~^ ERROR the requirement `T: Str` appears on the impl method + //~^ ERROR E0276 } } diff --git a/src/test/compile-fail/issue-15260.rs b/src/test/compile-fail/issue-15260.rs index 5ec82326d6..5f816d34c8 100644 --- a/src/test/compile-fail/issue-15260.rs +++ b/src/test/compile-fail/issue-15260.rs @@ -14,19 +14,28 @@ struct Foo { fn main() { let Foo { - a: _, //~ NOTE field `a` previously bound here - a: _ //~ ERROR field `a` bound multiple times in the pattern + a: _, //~ NOTE first use of `a` + a: _ + //~^ ERROR field `a` bound multiple times in the pattern + //~| NOTE multiple uses of `a` in pattern } = Foo { a: 29 }; let Foo { - a, //~ NOTE field `a` previously bound here - a: _ //~ ERROR field `a` bound multiple times in the pattern + a, //~ NOTE first use of `a` + a: _ + //~^ ERROR field `a` bound multiple times in the pattern + //~| NOTE multiple uses of `a` in pattern } = Foo { a: 29 }; let Foo { - a, //~ NOTE field `a` previously bound here - //~^ NOTE field `a` previously bound here - a: _, //~ ERROR field `a` bound multiple times in the pattern - a: x //~ ERROR field `a` bound multiple times in the pattern + a, + //~^ NOTE first use of `a` + //~| NOTE first use of `a` + a: _, + //~^ ERROR field `a` bound multiple times in the pattern + //~| NOTE multiple uses of `a` in pattern + a: x + //~^ ERROR field `a` bound multiple times in the pattern + //~| NOTE multiple uses of `a` in pattern } = Foo { a: 29 }; } diff --git a/src/test/compile-fail/issue-16058.rs b/src/test/compile-fail/issue-16058.rs index 671232e701..92c1e4b5f5 100644 --- a/src/test/compile-fail/issue-16058.rs +++ b/src/test/compile-fail/issue-16058.rs @@ -16,7 +16,7 @@ pub struct GslResult { impl GslResult { pub fn new() -> GslResult { - Result { //~ ERROR: `Result` does not name a struct or a struct variant + Result { //~ ERROR: expected struct, variant or union type, found enum `Result` val: 0f64, err: 0f64 } diff --git a/src/test/compile-fail/issue-1697.rs b/src/test/compile-fail/issue-1697.rs index dc09af0ada..1375200271 100644 --- a/src/test/compile-fail/issue-1697.rs +++ b/src/test/compile-fail/issue-1697.rs @@ -11,6 +11,6 @@ // Testing that we don't fail abnormally after hitting the errors use unresolved::*; //~ ERROR unresolved import `unresolved::*` [E0432] - //~^ Maybe a missing `extern crate unresolved`? + //~^ Maybe a missing `extern crate unresolved;`? fn main() {} diff --git a/src/test/compile-fail/issue-17001.rs b/src/test/compile-fail/issue-17001.rs index 218f68714f..413e8b464f 100644 --- a/src/test/compile-fail/issue-17001.rs +++ b/src/test/compile-fail/issue-17001.rs @@ -11,5 +11,5 @@ mod foo {} fn main() { - let p = foo { x: () }; //~ ERROR `foo` does not name a struct or a struct variant + let p = foo { x: () }; //~ ERROR expected struct, variant or union type, found module `foo` } diff --git a/src/test/compile-fail/issue-17025.rs b/src/test/compile-fail/issue-17025.rs index 2a1a3397d5..f250103b14 100644 --- a/src/test/compile-fail/issue-17025.rs +++ b/src/test/compile-fail/issue-17025.rs @@ -8,6 +8,8 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. +// ignore-test the unsized enum no longer compiles + enum A { B(char), C([Box]), diff --git a/src/test/compile-fail/issue-17405.rs b/src/test/compile-fail/issue-17405.rs index 2f2c252b94..5a6bd5ed58 100644 --- a/src/test/compile-fail/issue-17405.rs +++ b/src/test/compile-fail/issue-17405.rs @@ -14,6 +14,6 @@ enum Foo { fn main() { match Foo::Bar(1) { - Foo { i } => () //~ ERROR expected variant, struct or type alias, found enum `Foo` + Foo { i } => () //~ ERROR expected struct, variant or union type, found enum `Foo` } } diff --git a/src/test/compile-fail/issue-17518.rs b/src/test/compile-fail/issue-17518.rs index 0410fadeb7..2113e38c45 100644 --- a/src/test/compile-fail/issue-17518.rs +++ b/src/test/compile-fail/issue-17518.rs @@ -13,5 +13,5 @@ enum SomeEnum { } fn main() { - E { name: "foobar" }; //~ ERROR `E` does not name a structure + E { name: "foobar" }; //~ ERROR unresolved struct, variant or union type `E` } diff --git a/src/test/compile-fail/issue-17933.rs b/src/test/compile-fail/issue-17933.rs index 2313a3fe9c..049a0665c5 100644 --- a/src/test/compile-fail/issue-17933.rs +++ b/src/test/compile-fail/issue-17933.rs @@ -13,7 +13,7 @@ pub static X: usize = 1; fn main() { match 1 { self::X => { }, - //~^ ERROR expected variant, struct or constant, found static `X` + //~^ ERROR expected unit struct/variant or constant, found static `self::X` _ => { }, } } diff --git a/src/test/compile-fail/issue-18937.rs b/src/test/compile-fail/issue-18937.rs new file mode 100644 index 0000000000..8ac66bb44d --- /dev/null +++ b/src/test/compile-fail/issue-18937.rs @@ -0,0 +1,53 @@ +// Copyright 2016 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +// Regression test for #18937. + +#![deny(extra_requirement_in_impl)] + +use std::fmt; + +#[derive(Debug)] +struct MyString<'a>(&'a String); + +struct B { + list: Vec>, +} + +trait A<'a> { + fn foo(&mut self, f: F) + where F: fmt::Debug + 'a, + Self: Sized; +} + +impl<'a> A<'a> for B { + fn foo(&mut self, f: F) //~ ERROR E0276 + //~^ WARNING future release + where F: fmt::Debug + 'static, + { + self.list.push(Box::new(f)); + } +} + +fn main() { + let mut b = B { list: Vec::new() }; + + // Create a borrowed pointer, put it in `b`, then drop what's borrowing it + let a = "hello".to_string(); + b.foo(MyString(&a)); + + // Drop the data which `b` has a reference to + drop(a); + + // Use the data, probably segfaulting + for b in b.list.iter() { + println!("{:?}", b); + } +} diff --git a/src/test/compile-fail/issue-19086.rs b/src/test/compile-fail/issue-19086.rs index 56452449d4..ba571ce17f 100644 --- a/src/test/compile-fail/issue-19086.rs +++ b/src/test/compile-fail/issue-19086.rs @@ -18,6 +18,6 @@ fn main() { let f = FooB { x: 3, y: 4 }; match f { FooB(a, b) => println!("{} {}", a, b), -//~^ ERROR `FooB` does not name a tuple variant or a tuple struct + //~^ ERROR expected tuple struct/variant, found struct variant `FooB` } } diff --git a/src/test/compile-fail/issue-19244-2.rs b/src/test/compile-fail/issue-19244-2.rs index 7d7d7d7c8c..864f8f6b54 100644 --- a/src/test/compile-fail/issue-19244-2.rs +++ b/src/test/compile-fail/issue-19244-2.rs @@ -13,5 +13,5 @@ const STRUCT: MyStruct = MyStruct { field: 42 }; fn main() { let a: [isize; STRUCT.nonexistent_field]; - //~^ ERROR attempted access of field `nonexistent_field` + //~^ no field `nonexistent_field` on type `MyStruct` } diff --git a/src/test/compile-fail/issue-19482.rs b/src/test/compile-fail/issue-19482.rs index 21a50f24d5..b54f008f8c 100644 --- a/src/test/compile-fail/issue-19482.rs +++ b/src/test/compile-fail/issue-19482.rs @@ -11,8 +11,6 @@ // Test that a partially specified trait object with unspecified associated // type does not type-check. -// pretty-expanded FIXME #23616 - trait Foo { type A; diff --git a/src/test/compile-fail/issue-21449.rs b/src/test/compile-fail/issue-21449.rs index 090b8a0d16..cc44cf88f0 100644 --- a/src/test/compile-fail/issue-21449.rs +++ b/src/test/compile-fail/issue-21449.rs @@ -11,5 +11,6 @@ mod MyMod {} fn main() { - let myVar = MyMod { T: 0 }; //~ ERROR `MyMod` does not name a struct or a struct variant + let myVar = MyMod { T: 0 }; + //~^ ERROR expected struct, variant or union type, found module `MyMod` } diff --git a/src/test/compile-fail/issue-21837.rs b/src/test/compile-fail/issue-21837.rs new file mode 100644 index 0000000000..86506de1ea --- /dev/null +++ b/src/test/compile-fail/issue-21837.rs @@ -0,0 +1,20 @@ +// 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. + +pub trait Bound {} +pub struct Foo(T); + +pub trait Trait1 {} +impl Trait1 for Foo {} + +pub trait Trait2 {} +impl Trait2 for Foo {} //~ ERROR the trait bound `T: Bound` is not satisfied + +fn main() {} diff --git a/src/test/compile-fail/issue-23253.rs b/src/test/compile-fail/issue-23253.rs index e977cd135a..626604a87a 100644 --- a/src/test/compile-fail/issue-23253.rs +++ b/src/test/compile-fail/issue-23253.rs @@ -12,5 +12,5 @@ enum Foo { Bar } fn main() { Foo::Bar.a; - //~^ ERROR: attempted access of field `a` on type `Foo`, but no field with that name was found + //~^ no field `a` on type `Foo` } diff --git a/src/test/compile-fail/issue-24363.rs b/src/test/compile-fail/issue-24363.rs index 590c464371..03cae6e64e 100644 --- a/src/test/compile-fail/issue-24363.rs +++ b/src/test/compile-fail/issue-24363.rs @@ -9,7 +9,7 @@ // except according to those terms. fn main() { - 1.create_a_type_error[ //~ ERROR attempted access of field + 1.create_a_type_error[ //~ no field `create_a_type_error` on type `{integer}` ()+() //~ ERROR binary operation `+` cannot be applied // ^ ensure that we typeck the inner expression ^ ]; diff --git a/src/test/compile-fail/issue-24365.rs b/src/test/compile-fail/issue-24365.rs index a4df42a8c7..72df6fb599 100644 --- a/src/test/compile-fail/issue-24365.rs +++ b/src/test/compile-fail/issue-24365.rs @@ -17,13 +17,13 @@ pub enum Foo { } fn test(a: Foo) { - println!("{}", a.b); //~ ERROR attempted access of field + println!("{}", a.b); //~ no field `b` on type `Foo` } 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 + let z = (&x).attr_name_idx; //~ no field `attr_name_idx` on type `&Attribute` + let y = x.attr_name_idx; //~ no field `attr_name_idx` on type `Attribute` } diff --git a/src/test/compile-fail/issue-26158.rs b/src/test/compile-fail/issue-26158.rs new file mode 100644 index 0000000000..54f5313aed --- /dev/null +++ b/src/test/compile-fail/issue-26158.rs @@ -0,0 +1,16 @@ +// Copyright 2016 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +#![feature(slice_patterns)] + +fn main() { + let x: &[u32] = &[]; + let &[[ref _a, ref _b..]..] = x; //~ ERROR refutable pattern +} diff --git a/src/test/compile-fail/issue-26459.rs b/src/test/compile-fail/issue-26459.rs index 24b39eeff0..8be3d88bd5 100644 --- a/src/test/compile-fail/issue-26459.rs +++ b/src/test/compile-fail/issue-26459.rs @@ -11,6 +11,6 @@ fn main() { match 'a' { char{ch} => true - //~^ ERROR expected variant, struct or type alias, found builtin type `char` + //~^ ERROR expected struct, variant or union type, found builtin type `char` }; } diff --git a/src/test/compile-fail/issue-27033.rs b/src/test/compile-fail/issue-27033.rs index 2a015adb49..b8552aaee9 100644 --- a/src/test/compile-fail/issue-27033.rs +++ b/src/test/compile-fail/issue-27033.rs @@ -10,7 +10,7 @@ fn main() { match Some(1) { - None @ _ => {} //~ ERROR match bindings cannot shadow variants + None @ _ => {} //~ ERROR match bindings cannot shadow unit variants }; const C: u8 = 1; match 1 { diff --git a/src/test/compile-fail/issue-27815.rs b/src/test/compile-fail/issue-27815.rs index 7a329bac61..d9840abf0c 100644 --- a/src/test/compile-fail/issue-27815.rs +++ b/src/test/compile-fail/issue-27815.rs @@ -11,10 +11,12 @@ mod A {} fn main() { - let u = A { x: 1 }; //~ ERROR `A` does not name a struct or a struct variant - let v = u32 { x: 1 }; //~ ERROR `u32` does not name a struct or a struct variant + let u = A { x: 1 }; //~ ERROR expected struct, variant or union type, found module `A` + let v = u32 { x: 1 }; //~ ERROR expected struct, variant or union type, found builtin type `u32` match () { - A { x: 1 } => {} //~ ERROR expected variant, struct or type alias, found module `A` - u32 { x: 1 } => {} //~ ERROR expected variant, struct or type alias, found builtin type `u32 + A { x: 1 } => {} + //~^ ERROR expected struct, variant or union type, found module `A` + u32 { x: 1 } => {} + //~^ ERROR expected struct, variant or union type, found builtin type `u32` } } diff --git a/src/test/compile-fail/issue-2848.rs b/src/test/compile-fail/issue-2848.rs index e5503edfab..f5e0c545bb 100644 --- a/src/test/compile-fail/issue-2848.rs +++ b/src/test/compile-fail/issue-2848.rs @@ -19,7 +19,7 @@ mod bar { fn main() { use bar::foo::{alpha, charlie}; match alpha { - alpha | beta => {} //~ ERROR variable `beta` from pattern #2 is not bound in pattern #1 - charlie => {} + alpha | beta => {} //~ ERROR variable `beta` from pattern #2 is not bound in pattern #1 + charlie => {} //~| NOTE pattern doesn't bind `beta` } } diff --git a/src/test/compile-fail/issue-28992-empty.rs b/src/test/compile-fail/issue-28992-empty.rs index e492d48fda..d47fdda020 100644 --- a/src/test/compile-fail/issue-28992-empty.rs +++ b/src/test/compile-fail/issue-28992-empty.rs @@ -21,6 +21,7 @@ impl S { } fn main() { - if let C1(..) = 0 {} //~ ERROR expected variant or struct, found constant `C1` - if let S::C2(..) = 0 {} //~ ERROR `S::C2` does not name a tuple variant or a tuple struct + if let C1(..) = 0 {} //~ ERROR expected tuple struct/variant, found constant `C1` + if let S::C2(..) = 0 {} + //~^ ERROR expected tuple struct/variant, found associated constant `S::C2` } diff --git a/src/test/compile-fail/issue-3044.rs b/src/test/compile-fail/issue-3044.rs index b934cbe4b5..c7b276da57 100644 --- a/src/test/compile-fail/issue-3044.rs +++ b/src/test/compile-fail/issue-3044.rs @@ -10,7 +10,7 @@ fn main() { - let needlesArr: Vec = vec!('a', 'f'); + let needlesArr: Vec = vec!['a', 'f']; needlesArr.iter().fold(|x, y| { }); //~^^ ERROR this function takes 2 parameters but 1 parameter was supplied diff --git a/src/test/compile-fail/issue-31011.rs b/src/test/compile-fail/issue-31011.rs index b828b11030..716b0bbe77 100644 --- a/src/test/compile-fail/issue-31011.rs +++ b/src/test/compile-fail/issue-31011.rs @@ -11,7 +11,7 @@ macro_rules! log { ( $ctx:expr, $( $args:expr),* ) => { if $ctx.trace { - //~^ ERROR attempted access of field `trace` on type `&T`, but no field with that name + //~^ no field `trace` on type `&T` println!( $( $args, )* ); } } diff --git a/src/test/compile-fail/issue-32004.rs b/src/test/compile-fail/issue-32004.rs index 576451f729..7e1f4c28d2 100644 --- a/src/test/compile-fail/issue-32004.rs +++ b/src/test/compile-fail/issue-32004.rs @@ -18,12 +18,12 @@ struct S; fn main() { match Foo::Baz { Foo::Bar => {} - //~^ ERROR `Foo::Bar` does not name a unit variant, unit struct or a constant + //~^ ERROR expected unit struct/variant or constant, found tuple variant `Foo::Bar` _ => {} } match S { S(()) => {} - //~^ ERROR `S` does not name a tuple variant or a tuple struct + //~^ ERROR expected tuple struct/variant, found unit struct `S` } } diff --git a/src/test/compile-fail/issue-32086.rs b/src/test/compile-fail/issue-32086.rs index 926f58198d..dd236b76a6 100644 --- a/src/test/compile-fail/issue-32086.rs +++ b/src/test/compile-fail/issue-32086.rs @@ -12,6 +12,6 @@ struct S(u8); const C: S = S(10); fn main() { - let C(a) = S(11); //~ ERROR expected variant or struct, found constant `C` - let C(..) = S(11); //~ ERROR expected variant or struct, found constant `C` + let C(a) = S(11); //~ ERROR expected tuple struct/variant, found constant `C` + let C(..) = S(11); //~ ERROR expected tuple struct/variant, found constant `C` } diff --git a/src/test/compile-fail/issue-32922.rs b/src/test/compile-fail/issue-32922.rs index 491c087c10..317a47156c 100644 --- a/src/test/compile-fail/issue-32922.rs +++ b/src/test/compile-fail/issue-32922.rs @@ -17,7 +17,7 @@ macro_rules! foo { () => { let _ = bar!(); }} -macro_rules! bar { // test issue #31856 +macro_rules! m { // test issue #31856 ($n:ident) => ( let a = 1; let $n = a; diff --git a/src/test/compile-fail/issue-36116.rs b/src/test/compile-fail/issue-36116.rs new file mode 100644 index 0000000000..9abf2b5ec3 --- /dev/null +++ b/src/test/compile-fail/issue-36116.rs @@ -0,0 +1,23 @@ +// Copyright 2016 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +struct Foo { + _a: T, +} + +fn main() { + let f = Some(Foo { _a: 42 }).map(|a| a as Foo::); + //~^ ERROR unexpected token: `::` + //~| HELP use `<...>` instead of `::<...>` if you meant to specify type arguments + + let g: Foo:: = Foo { _a: 42 }; + //~^ ERROR unexpected token: `::` + //~| HELP use `<...>` instead of `::<...>` if you meant to specify type arguments +} diff --git a/src/test/compile-fail/E0422.rs b/src/test/compile-fail/issue-36881.rs similarity index 83% rename from src/test/compile-fail/E0422.rs rename to src/test/compile-fail/issue-36881.rs index 61e96b896a..cca20e968e 100644 --- a/src/test/compile-fail/E0422.rs +++ b/src/test/compile-fail/issue-36881.rs @@ -8,8 +8,7 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -fn main () { - let x = Foo { x: 1, y: 2 }; - //~^ ERROR E0422 - //~| NOTE not a structure +fn main() { + extern crate rand; + use rand::Rng; //~ ERROR unresolved import } diff --git a/src/test/compile-fail/issue-37026.rs b/src/test/compile-fail/issue-37026.rs new file mode 100644 index 0000000000..95fd5d1222 --- /dev/null +++ b/src/test/compile-fail/issue-37026.rs @@ -0,0 +1,18 @@ +// Copyright 2016 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +// aux-build:empty-struct.rs + +extern crate empty_struct; + +fn main() { + let empty_struct::XEmpty2 = (); //~ ERROR mismatched types + let empty_struct::XEmpty6(..) = (); //~ ERROR mismatched types +} diff --git a/src/test/compile-fail/issue-37534.rs b/src/test/compile-fail/issue-37534.rs new file mode 100644 index 0000000000..eb676601e8 --- /dev/null +++ b/src/test/compile-fail/issue-37534.rs @@ -0,0 +1,16 @@ +// Copyright 2016 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +struct Foo { } +//~^ ERROR trait `Hash` is not in scope [E0405] +//~^^ ERROR parameter `T` is never used [E0392] +//~^^^ WARN default bound relaxed for a type parameter, but this does nothing + +fn main() { } diff --git a/src/test/compile-fail/issue-5067.rs b/src/test/compile-fail/issue-5067.rs index b7b5553dc7..1c543a5fda 100644 --- a/src/test/compile-fail/issue-5067.rs +++ b/src/test/compile-fail/issue-5067.rs @@ -48,7 +48,7 @@ macro_rules! make_vec { } fn main() { - let _ = make_vec!(a 1, a 2, a 3); + let _ = make_vec![a 1, a 2, a 3]; } diff --git a/src/test/compile-fail/issue-5883.rs b/src/test/compile-fail/issue-5883.rs index 019a7bdc73..e14d9f3a35 100644 --- a/src/test/compile-fail/issue-5883.rs +++ b/src/test/compile-fail/issue-5883.rs @@ -20,6 +20,4 @@ fn new_struct(r: A+'static) Struct { r: r } } -trait Curve {} -enum E {X(Curve+'static)} fn main() {} diff --git a/src/test/compile-fail/issue-5927.rs b/src/test/compile-fail/issue-5927.rs index 3a8ff12429..7668a2117a 100644 --- a/src/test/compile-fail/issue-5927.rs +++ b/src/test/compile-fail/issue-5927.rs @@ -11,7 +11,7 @@ fn main() { let z = match 3 { - x(1) => x(1) //~ ERROR unresolved variant or struct `x` + x(1) => x(1) //~ ERROR unresolved tuple struct/variant `x` //~^ ERROR unresolved name `x` }; assert!(z == 3); diff --git a/src/test/compile-fail/issue-6804.rs b/src/test/compile-fail/issue-6804.rs index f6b7e13c4f..f7d3ce60c6 100644 --- a/src/test/compile-fail/issue-6804.rs +++ b/src/test/compile-fail/issue-6804.rs @@ -8,29 +8,24 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -#![feature(rustc_attrs)] -#![feature(slice_patterns)] -#![allow(dead_code)] - // Matching against NaN should result in a warning +#![feature(slice_patterns)] +#![allow(unused)] + use std::f64::NAN; -#[rustc_error] -fn main() { //~ ERROR compilation successful +fn main() { let x = NAN; match x { - NAN => {}, + NAN => {}, //~ ERROR floating point constants cannot be used + //~| WARNING hard error _ => {}, }; - //~^^^ WARNING unmatchable NaN in pattern, use the is_nan method in a guard instead - //~| WARNING floating point constants cannot be used - //~| WARNING this was previously accepted + match [x, 1.0] { - [NAN, _] => {}, + [NAN, _] => {}, //~ ERROR floating point constants cannot be used + //~| WARNING hard error _ => {}, }; - //~^^^ WARNING unmatchable NaN in pattern, use the is_nan method in a guard instead - //~| WARNING floating point constants cannot be used - //~| WARNING this was previously accepted } diff --git a/src/test/compile-fail/issue-7970a.rs b/src/test/compile-fail/issue-7970a.rs index 114db74f42..b97c303777 100644 --- a/src/test/compile-fail/issue-7970a.rs +++ b/src/test/compile-fail/issue-7970a.rs @@ -8,7 +8,11 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. +macro_rules! one_arg_macro { + ($fmt:expr) => (print!(concat!($fmt, "\n"))); +} + fn main() { - println!(); + one_arg_macro!(); //~^ ERROR unexpected end of macro invocation } diff --git a/src/test/run-pass/issue-pr29383.rs b/src/test/compile-fail/issue-pr29383.rs similarity index 74% rename from src/test/run-pass/issue-pr29383.rs rename to src/test/compile-fail/issue-pr29383.rs index defb2c164d..b60c537e1e 100644 --- a/src/test/run-pass/issue-pr29383.rs +++ b/src/test/compile-fail/issue-pr29383.rs @@ -8,8 +8,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -#![allow(match_of_unit_variant_via_paren_dotdot)] - enum E { A, B, @@ -18,7 +16,7 @@ enum E { fn main() { match None { None => {} - Some(E::A(..)) => {} - Some(E::B(..)) => {} + Some(E::A(..)) => {} //~ ERROR expected tuple struct/variant, found unit variant `E::A` + Some(E::B(..)) => {} //~ ERROR expected tuple struct/variant, found unit variant `E::B` } } diff --git a/src/test/parse-fail/keyword-self-as-identifier.rs b/src/test/compile-fail/keyword-self-as-identifier.rs similarity index 81% rename from src/test/parse-fail/keyword-self-as-identifier.rs rename to src/test/compile-fail/keyword-self-as-identifier.rs index f8b93a1796..650874711a 100644 --- a/src/test/parse-fail/keyword-self-as-identifier.rs +++ b/src/test/compile-fail/keyword-self-as-identifier.rs @@ -8,8 +8,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -// compile-flags: -Z parse-only - fn main() { - let Self = "foo"; //~ error: expected identifier, found keyword `Self` + let Self = "foo"; //~ ERROR unresolved unit struct/variant or constant `Self` } diff --git a/src/test/parse-fail/keyword-super-as-identifier.rs b/src/test/compile-fail/keyword-super-as-identifier.rs similarity index 81% rename from src/test/parse-fail/keyword-super-as-identifier.rs rename to src/test/compile-fail/keyword-super-as-identifier.rs index a48683a4f5..531705563e 100644 --- a/src/test/parse-fail/keyword-super-as-identifier.rs +++ b/src/test/compile-fail/keyword-super-as-identifier.rs @@ -8,8 +8,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -// compile-flags: -Z parse-only - fn main() { - let super = "foo"; //~ error: expected identifier, found keyword `super` + let super = "foo"; //~ ERROR unresolved unit struct/variant or constant `super` } diff --git a/src/test/parse-fail/keyword-super.rs b/src/test/compile-fail/keyword-super.rs similarity index 81% rename from src/test/parse-fail/keyword-super.rs rename to src/test/compile-fail/keyword-super.rs index 671be8c44b..9ac9e800c8 100644 --- a/src/test/parse-fail/keyword-super.rs +++ b/src/test/compile-fail/keyword-super.rs @@ -8,8 +8,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -// compile-flags: -Z parse-only - fn main() { - let super: isize; //~ ERROR expected identifier, found keyword `super` + let super: isize; //~ ERROR unresolved unit struct/variant or constant `super` } diff --git a/src/test/compile-fail/lexical-scopes.rs b/src/test/compile-fail/lexical-scopes.rs index 505a91f223..1ab59e790d 100644 --- a/src/test/compile-fail/lexical-scopes.rs +++ b/src/test/compile-fail/lexical-scopes.rs @@ -10,7 +10,7 @@ struct T { i: i32 } fn f() { - let t = T { i: 0 }; //~ ERROR `T` does not name a struct or a struct variant + let t = T { i: 0 }; //~ ERROR expected struct, variant or union type, found type parameter `T` } mod Foo { diff --git a/src/test/compile-fail/lifetime-underscore.rs b/src/test/compile-fail/lifetime-underscore.rs index 102d3576e5..b768009132 100644 --- a/src/test/compile-fail/lifetime-underscore.rs +++ b/src/test/compile-fail/lifetime-underscore.rs @@ -8,8 +8,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -#![deny(lifetime_underscore)] - fn _f<'_>() //~ ERROR invalid lifetime name `'_` //~^ WARN this was previously accepted -> &'_ u8 //~ ERROR invalid lifetime name `'_` diff --git a/src/test/compile-fail/lint-group-style.rs b/src/test/compile-fail/lint-group-style.rs index 393e46ab53..b2e6072c98 100644 --- a/src/test/compile-fail/lint-group-style.rs +++ b/src/test/compile-fail/lint-group-style.rs @@ -24,7 +24,7 @@ mod test { mod bad { fn CamelCase() {} //~ ERROR function `CamelCase` should have a snake case name - static bad: isize = 1; //~ ERROR static constant `bad` should have an upper case name + static bad: isize = 1; //~ ERROR static variable `bad` should have an upper case name } mod warn { diff --git a/src/test/compile-fail/lint-non-uppercase-statics.rs b/src/test/compile-fail/lint-non-uppercase-statics.rs index e1fbc73bbe..463a93612c 100644 --- a/src/test/compile-fail/lint-non-uppercase-statics.rs +++ b/src/test/compile-fail/lint-non-uppercase-statics.rs @@ -11,6 +11,9 @@ #![forbid(non_upper_case_globals)] #![allow(dead_code)] -static foo: isize = 1; //~ ERROR static constant `foo` should have an upper case name such as `FOO` +static foo: isize = 1; //~ ERROR static variable `foo` should have an upper case name such as `FOO` + +static mut bar: isize = 1; + //~^ ERROR static variable `bar` should have an upper case name such as `BAR` fn main() { } diff --git a/src/test/compile-fail/lint-qualification.rs b/src/test/compile-fail/lint-qualification.rs index 0ad3d2c5e7..af9b21dadd 100644 --- a/src/test/compile-fail/lint-qualification.rs +++ b/src/test/compile-fail/lint-qualification.rs @@ -18,4 +18,11 @@ fn main() { use foo::bar; foo::bar(); //~ ERROR: unnecessary qualification bar(); + + let _ = || -> Result<(), ()> { try!(Ok(())); Ok(()) }; // issue #37345 + + macro_rules! m { + () => { $crate::foo::bar(); } + } + m!(); // issue #37357 } diff --git a/src/test/compile-fail/lint-unused-extern-crate.rs b/src/test/compile-fail/lint-unused-extern-crate.rs index 854c51d076..52cb84f662 100644 --- a/src/test/compile-fail/lint-unused-extern-crate.rs +++ b/src/test/compile-fail/lint-unused-extern-crate.rs @@ -26,6 +26,8 @@ extern crate rand; // no error, the use marks it as used extern crate lint_unused_extern_crate as other; // no error, the use * marks it as used +#[macro_use] extern crate core; // no error, the `#[macro_use]` marks it as used + #[allow(unused_imports)] use rand::isaac::IsaacRng; diff --git a/src/test/compile-fail/lint-unused-imports.rs b/src/test/compile-fail/lint-unused-imports.rs index 239f380e6c..3f91c3e1e5 100644 --- a/src/test/compile-fail/lint-unused-imports.rs +++ b/src/test/compile-fail/lint-unused-imports.rs @@ -17,19 +17,19 @@ use std::mem::*; // shouldn't get errors for not using // everything imported // Should get errors for both 'Some' and 'None' -use std::option::Option::{Some, None}; //~ ERROR unused import - //~^ ERROR unused import +use std::option::Option::{Some, None}; //~ ERROR unused import: `Some` + //~^ ERROR unused import: `None` -use test::A; //~ ERROR unused import +use test::A; //~ ERROR unused import: `test::A` // Be sure that if we just bring some methods into scope that they're also // counted as being used. use test::B; // But only when actually used: do not get confused by the method with the same name. -use test::B2; //~ ERROR unused import +use test::B2; //~ ERROR unused import: `test::B2` // Make sure this import is warned about when at least one of its imported names // is unused -use test2::{foo, bar}; //~ ERROR unused import +use test2::{foo, bar}; //~ ERROR unused import: `bar` mod test2 { pub fn foo() {} @@ -57,7 +57,7 @@ mod bar { pub mod c { use foo::Point; - use foo::Square; //~ ERROR unused import + use foo::Square; //~ ERROR unused import: `foo::Square` pub fn cc(_p: Point) -> super::Square { fn f() -> super::Square { super::Square @@ -73,7 +73,7 @@ mod bar { } fn g() { - use self::g; //~ ERROR unused import + use self::g; //~ ERROR unused import: `self::g` fn f() { self::g(); } @@ -82,7 +82,7 @@ fn g() { // c.f. issue #35135 #[allow(unused_variables)] fn h() { - use test2::foo; //~ ERROR unused import + use test2::foo; //~ ERROR unused import: `test2::foo` let foo = 0; } diff --git a/src/test/compile-fail/lint-unused-mut-variables.rs b/src/test/compile-fail/lint-unused-mut-variables.rs index 8165dd0fa2..21cfadb9c7 100644 --- a/src/test/compile-fail/lint-unused-mut-variables.rs +++ b/src/test/compile-fail/lint-unused-mut-variables.rs @@ -21,7 +21,7 @@ fn main() { let mut a = 3; //~ ERROR: variable does not need to be mutable let mut a = 2; //~ ERROR: variable does not need to be mutable let mut b = 3; //~ ERROR: variable does not need to be mutable - let mut a = vec!(3); //~ ERROR: variable does not need to be mutable + let mut a = vec![3]; //~ ERROR: variable does not need to be mutable let (mut a, b) = (1, 2); //~ ERROR: variable does not need to be mutable let mut a; //~ ERROR: variable does not need to be mutable a = 3; @@ -88,5 +88,5 @@ fn callback(f: F) where F: FnOnce() {} #[allow(unused_mut)] fn foo(mut a: isize) { let mut a = 3; - let mut b = vec!(2); + let mut b = vec![2]; } diff --git a/src/test/compile-fail/macro-shadowing.rs b/src/test/compile-fail/macro-shadowing.rs new file mode 100644 index 0000000000..8381dc34a6 --- /dev/null +++ b/src/test/compile-fail/macro-shadowing.rs @@ -0,0 +1,39 @@ +// Copyright 2016 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +// aux-build:two_macros.rs + +macro_rules! foo { () => {} } +macro_rules! macro_one { () => {} } +#[macro_use(macro_two)] extern crate two_macros; + +macro_rules! m1 { () => { + macro_rules! foo { () => {} } //~ ERROR `foo` is already in scope + //~^ NOTE macro-expanded `macro_rules!`s may not shadow existing macros + + #[macro_use] //~ ERROR `macro_two` is already in scope + //~^ NOTE macro-expanded `#[macro_use]`s may not shadow existing macros + extern crate two_macros as __; +}} +m1!(); //~ NOTE in this expansion + //~| NOTE in this expansion + //~| NOTE in this expansion + //~| NOTE in this expansion + +foo!(); + +macro_rules! m2 { () => { + macro_rules! foo { () => {} } + foo!(); +}} +m2!(); +//^ Since `foo` is not used outside this expansion, it is not a shadowing error. + +fn main() {} diff --git a/src/test/compile-fail/macro-use-scope.rs b/src/test/compile-fail/macro-use-scope.rs index 5256396a24..9d389413ba 100644 --- a/src/test/compile-fail/macro-use-scope.rs +++ b/src/test/compile-fail/macro-use-scope.rs @@ -19,10 +19,10 @@ fn f() { #[macro_use(macro_one)] // Check that this macro is usable in the above function extern crate two_macros; +fn g() { + macro_two!(); +} macro_rules! m { () => { - fn g() { - macro_two!(); - } #[macro_use(macro_two)] // Check that this macro is usable in the above function extern crate two_macros as _two_macros; } } diff --git a/src/test/compile-fail/match-byte-array-patterns.rs b/src/test/compile-fail/match-byte-array-patterns.rs new file mode 100644 index 0000000000..86323656b8 --- /dev/null +++ b/src/test/compile-fail/match-byte-array-patterns.rs @@ -0,0 +1,73 @@ +// Copyright 2016 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +#![feature(advanced_slice_patterns, slice_patterns)] + +fn main() { + let buf = &[0, 1, 2, 3]; + + match buf { + b"AAAA" => {}, + &[0x41, 0x41, 0x41, 0x41] => {} //~ ERROR unreachable pattern + _ => {} + } + + match buf { + &[0x41, 0x41, 0x41, 0x41] => {} + b"AAAA" => {}, //~ ERROR unreachable pattern + _ => {} + } + + match buf { + &[_, 0x41, 0x41, 0x41] => {}, + b"AAAA" => {}, //~ ERROR unreachable pattern + _ => {} + } + + match buf { + &[0x41, .., 0x41] => {} + b"AAAA" => {}, //~ ERROR unreachable pattern + _ => {} + } + + match buf { //~ ERROR non-exhaustive + b"AAAA" => {} + } + + let buf: &[u8] = buf; + + match buf { + b"AAAA" => {}, + &[0x41, 0x41, 0x41, 0x41] => {} //~ ERROR unreachable pattern + _ => {} + } + + match buf { + &[0x41, 0x41, 0x41, 0x41] => {} + b"AAAA" => {}, //~ ERROR unreachable pattern + _ => {} + } + + match buf { + &[_, 0x41, 0x41, 0x41] => {}, + b"AAAA" => {}, //~ ERROR unreachable pattern + _ => {} + } + + match buf { + &[0x41, .., 0x41] => {} + b"AAAA" => {}, //~ ERROR unreachable pattern + _ => {} + } + + match buf { //~ ERROR non-exhaustive + b"AAAA" => {} + } +} diff --git a/src/test/compile-fail/match-pattern-field-mismatch-2.rs b/src/test/compile-fail/match-pattern-field-mismatch-2.rs index a4ba93ea17..aed9130d60 100644 --- a/src/test/compile-fail/match-pattern-field-mismatch-2.rs +++ b/src/test/compile-fail/match-pattern-field-mismatch-2.rs @@ -20,7 +20,7 @@ fn main() { color::rgb(_, _, _) => { } color::cmyk(_, _, _, _) => { } color::no_color(_) => { } - //~^ ERROR `color::no_color` does not name a tuple variant or a tuple struct + //~^ ERROR expected tuple struct/variant, found unit variant `color::no_color` } } } diff --git a/src/test/compile-fail/match-pattern-field-mismatch.rs b/src/test/compile-fail/match-pattern-field-mismatch.rs index 8426ecdaf9..ddd5d63317 100644 --- a/src/test/compile-fail/match-pattern-field-mismatch.rs +++ b/src/test/compile-fail/match-pattern-field-mismatch.rs @@ -18,7 +18,7 @@ fn main() { fn foo(c: color) { match c { color::rgb(_, _) => { } - //~^ ERROR this pattern has 2 fields, but the corresponding variant has 3 fields + //~^ ERROR this pattern has 2 fields, but the corresponding tuple variant has 3 fields color::cmyk(_, _, _, _) => { } color::no_color => { } } diff --git a/src/test/compile-fail/match-vec-unreachable.rs b/src/test/compile-fail/match-vec-unreachable.rs index 57e3a58b56..4d9b3aea11 100644 --- a/src/test/compile-fail/match-vec-unreachable.rs +++ b/src/test/compile-fail/match-vec-unreachable.rs @@ -29,7 +29,7 @@ fn main() { _ => { } } - let x: Vec = vec!('a', 'b', 'c'); + let x: Vec = vec!['a', 'b', 'c']; let x: &[char] = &x; match *x { ['a', 'b', 'c', ref _tail..] => {} diff --git a/src/test/compile-fail/meta-expected-error-correct-rev.rs b/src/test/compile-fail/meta-expected-error-correct-rev.rs index 95b4e1a33c..bd70879d13 100644 --- a/src/test/compile-fail/meta-expected-error-correct-rev.rs +++ b/src/test/compile-fail/meta-expected-error-correct-rev.rs @@ -9,7 +9,6 @@ // except according to those terms. // revisions: a -// pretty-expanded FIXME #23616 // Counterpart to `meta-expected-error-wrong-rev.rs` diff --git a/src/test/compile-fail/meta-expected-error-wrong-rev.rs b/src/test/compile-fail/meta-expected-error-wrong-rev.rs index 084c6ed4f4..3c13050812 100644 --- a/src/test/compile-fail/meta-expected-error-wrong-rev.rs +++ b/src/test/compile-fail/meta-expected-error-wrong-rev.rs @@ -10,7 +10,6 @@ // revisions: a // should-fail -// pretty-expanded FIXME #23616 // This is a "meta-test" of the compilertest framework itself. In // particular, it includes the right error message, but the message diff --git a/src/test/compile-fail/method-path-in-pattern.rs b/src/test/compile-fail/method-path-in-pattern.rs index ef011c89c6..aaa89b2282 100644 --- a/src/test/compile-fail/method-path-in-pattern.rs +++ b/src/test/compile-fail/method-path-in-pattern.rs @@ -22,13 +22,13 @@ impl MyTrait for Foo {} fn main() { match 0u32 { - Foo::bar => {} //~ ERROR `Foo::bar` does not name a unit variant, unit struct or a constant + Foo::bar => {} //~ ERROR expected unit struct/variant or constant, found method `Foo::bar` } match 0u32 { - ::bar => {} //~ ERROR `bar` does not name a unit variant, unit struct or a constant + ::bar => {} //~ ERROR expected unit struct/variant or constant, found method `bar` } match 0u32 { ::trait_bar => {} - //~^ ERROR `trait_bar` does not name a unit variant, unit struct or a constant + //~^ ERROR expected unit struct/variant or constant, found method `trait_bar` } } diff --git a/src/test/compile-fail/method-resolvable-path-in-pattern.rs b/src/test/compile-fail/method-resolvable-path-in-pattern.rs index 3ae792f9c0..4d8959466b 100644 --- a/src/test/compile-fail/method-resolvable-path-in-pattern.rs +++ b/src/test/compile-fail/method-resolvable-path-in-pattern.rs @@ -19,6 +19,6 @@ impl MyTrait for Foo {} fn main() { match 0u32 { ::trait_bar => {} - //~^ ERROR expected variant, struct or constant, found method `trait_bar` + //~^ ERROR expected unit struct/variant or constant, found method `MyTrait::trait_bar` } } diff --git a/src/test/compile-fail/moves-based-on-type-access-to-field.rs b/src/test/compile-fail/moves-based-on-type-access-to-field.rs index b8572fbd21..63fb4ff02a 100644 --- a/src/test/compile-fail/moves-based-on-type-access-to-field.rs +++ b/src/test/compile-fail/moves-based-on-type-access-to-field.rs @@ -16,7 +16,7 @@ fn consume(_s: String) {} fn touch(_a: &A) {} fn f20() { - let x = vec!("hi".to_string()); + let x = vec!["hi".to_string()]; consume(x.into_iter().next().unwrap()); touch(&x[0]); //~ ERROR use of moved value: `x` } diff --git a/src/test/compile-fail/moves-based-on-type-exprs.rs b/src/test/compile-fail/moves-based-on-type-exprs.rs index 9ad44567a4..194f278259 100644 --- a/src/test/compile-fail/moves-based-on-type-exprs.rs +++ b/src/test/compile-fail/moves-based-on-type-exprs.rs @@ -29,7 +29,7 @@ fn f20() { } fn f21() { - let x = vec!(1, 2, 3); + let x = vec![1, 2, 3]; let _y = (x[0], 3); touch(&x); } @@ -77,24 +77,24 @@ fn f70() { fn f80() { let x = "hi".to_string(); - let _y = vec!(x); + let _y = vec![x]; touch(&x); //~ ERROR use of moved value: `x` } fn f100() { - let x = vec!("hi".to_string()); + let x = vec!["hi".to_string()]; let _y = x.into_iter().next().unwrap(); touch(&x); //~ ERROR use of moved value: `x` } fn f110() { - let x = vec!("hi".to_string()); + let x = vec!["hi".to_string()]; let _y = [x.into_iter().next().unwrap(); 1]; touch(&x); //~ ERROR use of moved value: `x` } fn f120() { - let mut x = vec!("hi".to_string(), "ho".to_string()); + let mut x = vec!["hi".to_string(), "ho".to_string()]; x.swap(0, 1); touch(&x[0]); touch(&x[1]); diff --git a/src/test/compile-fail/name-clash-nullary.rs b/src/test/compile-fail/name-clash-nullary.rs index 2e2d53c4d4..4c76c4b8b0 100644 --- a/src/test/compile-fail/name-clash-nullary.rs +++ b/src/test/compile-fail/name-clash-nullary.rs @@ -11,7 +11,7 @@ use std::option::*; fn main() { - let None: isize = 42; //~ ERROR let bindings cannot shadow variants + let None: isize = 42; //~ ERROR let bindings cannot shadow unit variants log(debug, None); //~^ ERROR unresolved name `debug` //~| ERROR unresolved name `log` diff --git a/src/test/compile-fail/namespace-mix-new.rs b/src/test/compile-fail/namespace-mix-new.rs new file mode 100644 index 0000000000..0abe8bd439 --- /dev/null +++ b/src/test/compile-fail/namespace-mix-new.rs @@ -0,0 +1,167 @@ +// Copyright 2016 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +// aux-build:namespace-mix-new.rs + +#![feature(item_like_imports, relaxed_adts)] + +extern crate namespace_mix_new; +use namespace_mix_new::*; + +mod c { + pub struct S {} + pub struct TS(); + pub struct US; + pub enum E { + V {}, + TV(), + UV, + } + + pub struct Item; +} + +// Use something emitting the type argument name, e.g. unsatisfied bound. +trait Impossible {} +fn check(_: T) {} + +mod m1 { + pub use ::c::*; + pub type S = ::c::Item; +} +mod m2 { + pub use ::c::*; + pub const S: ::c::Item = ::c::Item; +} + +fn f12() { + check(m1::S{}); //~ ERROR c::Item + check(m1::S); //~ ERROR unresolved name + check(m2::S{}); //~ ERROR c::S + check(m2::S); //~ ERROR c::Item +} +fn xf12() { + check(xm1::S{}); //~ ERROR c::Item + check(xm1::S); //~ ERROR unresolved name + check(xm2::S{}); //~ ERROR c::S + check(xm2::S); //~ ERROR c::Item +} + +mod m3 { + pub use ::c::*; + pub type TS = ::c::Item; +} +mod m4 { + pub use ::c::*; + pub const TS: ::c::Item = ::c::Item; +} + +fn f34() { + check(m3::TS{}); //~ ERROR c::Item + check(m3::TS); //~ ERROR c::TS + check(m4::TS{}); //~ ERROR c::TS + check(m4::TS); //~ ERROR c::Item +} +fn xf34() { + check(xm3::TS{}); //~ ERROR c::Item + check(xm3::TS); //~ ERROR c::TS + check(xm4::TS{}); //~ ERROR c::TS + check(xm4::TS); //~ ERROR c::Item +} + +mod m5 { + pub use ::c::*; + pub type US = ::c::Item; +} +mod m6 { + pub use ::c::*; + pub const US: ::c::Item = ::c::Item; +} + +fn f56() { + check(m5::US{}); //~ ERROR c::Item + check(m5::US); //~ ERROR c::US + check(m6::US{}); //~ ERROR c::US + check(m6::US); //~ ERROR c::Item +} +fn xf56() { + check(xm5::US{}); //~ ERROR c::Item + check(xm5::US); //~ ERROR c::US + check(xm6::US{}); //~ ERROR c::US + check(xm6::US); //~ ERROR c::Item +} + +mod m7 { + pub use ::c::E::*; + pub type V = ::c::Item; +} +mod m8 { + pub use ::c::E::*; + pub const V: ::c::Item = ::c::Item; +} + +fn f78() { + check(m7::V{}); //~ ERROR c::Item + check(m7::V); //~ ERROR name of a struct or struct variant + check(m8::V{}); //~ ERROR c::E + check(m8::V); //~ ERROR c::Item +} +fn xf78() { + check(xm7::V{}); //~ ERROR c::Item + check(xm7::V); //~ ERROR name of a struct or struct variant + check(xm8::V{}); //~ ERROR c::E + check(xm8::V); //~ ERROR c::Item +} + +mod m9 { + pub use ::c::E::*; + pub type TV = ::c::Item; +} +mod mA { + pub use ::c::E::*; + pub const TV: ::c::Item = ::c::Item; +} + +fn f9A() { + check(m9::TV{}); //~ ERROR c::Item + check(m9::TV); //~ ERROR c::E + check(mA::TV{}); //~ ERROR c::E + check(mA::TV); //~ ERROR c::Item +} +fn xf9A() { + check(xm9::TV{}); //~ ERROR c::Item + check(xm9::TV); //~ ERROR c::E + check(xmA::TV{}); //~ ERROR c::E + check(xmA::TV); //~ ERROR c::Item +} + +mod mB { + pub use ::c::E::*; + pub type UV = ::c::Item; +} +mod mC { + pub use ::c::E::*; + pub const UV: ::c::Item = ::c::Item; +} + +fn fBC() { + check(mB::UV{}); //~ ERROR c::Item + check(mB::UV); //~ ERROR c::E + check(mC::UV{}); //~ ERROR c::E + check(mC::UV); //~ ERROR c::Item +} +fn xfBC() { + check(xmB::UV{}); //~ ERROR c::Item + check(xmB::UV); //~ ERROR c::E + check(xmC::UV{}); //~ ERROR c::E + check(xmC::UV); //~ ERROR c::Item +} + +fn main() {} diff --git a/src/test/compile-fail/namespace-mix-old.rs b/src/test/compile-fail/namespace-mix-old.rs new file mode 100644 index 0000000000..ad67664419 --- /dev/null +++ b/src/test/compile-fail/namespace-mix-old.rs @@ -0,0 +1,174 @@ +// Copyright 2016 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +// FIXME: Remove when `item_like_imports` is stabilized. + +// aux-build:namespace-mix-old.rs + +#![feature(relaxed_adts)] + +extern crate namespace_mix_old; +use namespace_mix_old::{xm1, xm2, xm3, xm4, xm5, xm6, xm7, xm8, xm9, xmA, xmB, xmC}; + +mod c { + pub struct S {} + pub struct TS(); + pub struct US; + pub enum E { + V {}, + TV(), + UV, + } + + pub struct Item; +} + +mod proxy { + pub use c::*; + pub use c::E::*; +} + +// Use something emitting the type argument name, e.g. unsatisfied bound. +trait Impossible {} +fn check(_: T) {} + +mod m1 { + pub use ::proxy::*; + pub type S = ::c::Item; +} +mod m2 { + pub use ::proxy::*; + pub const S: ::c::Item = ::c::Item; +} + +fn f12() { + check(m1::S{}); //~ ERROR c::Item + check(m1::S); //~ ERROR unresolved name + check(m2::S{}); //~ ERROR c::S + check(m2::S); //~ ERROR c::Item +} +fn xf12() { + check(xm1::S{}); //~ ERROR c::Item + check(xm1::S); //~ ERROR unresolved name + check(xm2::S{}); //~ ERROR c::S + check(xm2::S); //~ ERROR c::Item +} + +mod m3 { + pub use ::proxy::*; + pub type TS = ::c::Item; +} +mod m4 { + pub use ::proxy::*; + pub const TS: ::c::Item = ::c::Item; +} + +fn f34() { + check(m3::TS{}); //~ ERROR c::Item + check(m3::TS); //~ ERROR c::TS + check(m4::TS{}); //~ ERROR c::TS + check(m4::TS); //~ ERROR c::Item +} +fn xf34() { + check(xm3::TS{}); //~ ERROR c::Item + check(xm3::TS); //~ ERROR c::TS + check(xm4::TS{}); //~ ERROR c::TS + check(xm4::TS); //~ ERROR c::Item +} + +mod m5 { + pub use ::proxy::*; + pub type US = ::c::Item; +} +mod m6 { + pub use ::proxy::*; + pub const US: ::c::Item = ::c::Item; +} + +fn f56() { + check(m5::US{}); //~ ERROR c::Item + check(m5::US); //~ ERROR c::US + check(m6::US{}); //~ ERROR c::US + check(m6::US); //~ ERROR c::Item +} +fn xf56() { + check(xm5::US{}); //~ ERROR c::Item + check(xm5::US); //~ ERROR c::US + check(xm6::US{}); //~ ERROR c::US + check(xm6::US); //~ ERROR c::Item +} + +mod m7 { + pub use ::proxy::*; + pub type V = ::c::Item; +} +mod m8 { + pub use ::proxy::*; + pub const V: ::c::Item = ::c::Item; +} + +fn f78() { + check(m7::V{}); //~ ERROR c::Item + check(m7::V); //~ ERROR name of a struct or struct variant + check(m8::V{}); //~ ERROR c::E + check(m8::V); //~ ERROR c::Item +} +fn xf78() { + check(xm7::V{}); //~ ERROR c::Item + check(xm7::V); //~ ERROR name of a struct or struct variant + check(xm8::V{}); //~ ERROR c::E + check(xm8::V); //~ ERROR c::Item +} + +mod m9 { + pub use ::proxy::*; + pub type TV = ::c::Item; +} +mod mA { + pub use ::proxy::*; + pub const TV: ::c::Item = ::c::Item; +} + +fn f9A() { + check(m9::TV{}); //~ ERROR c::Item + check(m9::TV); //~ ERROR c::E + check(mA::TV{}); //~ ERROR c::E + check(mA::TV); //~ ERROR c::Item +} +fn xf9A() { + check(xm9::TV{}); //~ ERROR c::Item + check(xm9::TV); //~ ERROR c::E + check(xmA::TV{}); //~ ERROR c::E + check(xmA::TV); //~ ERROR c::Item +} + +mod mB { + pub use ::proxy::*; + pub type UV = ::c::Item; +} +mod mC { + pub use ::proxy::*; + pub const UV: ::c::Item = ::c::Item; +} + +fn fBC() { + check(mB::UV{}); //~ ERROR c::Item + check(mB::UV); //~ ERROR c::E + check(mC::UV{}); //~ ERROR c::E + check(mC::UV); //~ ERROR c::Item +} +fn xfBC() { + check(xmB::UV{}); //~ ERROR c::Item + check(xmB::UV); //~ ERROR c::E + check(xmC::UV{}); //~ ERROR c::E + check(xmC::UV); //~ ERROR c::Item +} + +fn main() {} diff --git a/src/test/compile-fail/no-capture-arc.rs b/src/test/compile-fail/no-capture-arc.rs index 7b7b3c414d..5e1d22bf63 100644 --- a/src/test/compile-fail/no-capture-arc.rs +++ b/src/test/compile-fail/no-capture-arc.rs @@ -14,7 +14,7 @@ use std::sync::Arc; use std::thread; fn main() { - let v = vec!(1, 2, 3, 4, 5, 6, 7, 8, 9, 10); + let v = vec![1, 2, 3, 4, 5, 6, 7, 8, 9, 10]; let arc_v = Arc::new(v); thread::spawn(move|| { diff --git a/src/test/compile-fail/no-link.rs b/src/test/compile-fail/no-link.rs index 957b6cda55..8f6da99806 100644 --- a/src/test/compile-fail/no-link.rs +++ b/src/test/compile-fail/no-link.rs @@ -13,6 +13,6 @@ extern crate libc; fn main() { unsafe { - libc::abs(0); //~ ERROR Use of undeclared type or module `libc` + libc::abs(0); //~ ERROR unresolved name } } diff --git a/src/test/compile-fail/no-patterns-in-args-2.rs b/src/test/compile-fail/no-patterns-in-args-2.rs new file mode 100644 index 0000000000..385d012cad --- /dev/null +++ b/src/test/compile-fail/no-patterns-in-args-2.rs @@ -0,0 +1,23 @@ +// Copyright 2016 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +#![deny(patterns_in_fns_without_body)] + +trait Tr { + fn f1(mut arg: u8); //~ ERROR patterns aren't allowed in methods without bodies + //~^ WARN was previously accepted + fn f2(&arg: u8); //~ ERROR patterns aren't allowed in methods without bodies + //~^ WARN was previously accepted + fn g1(arg: u8); // OK + fn g2(_: u8); // OK + fn g3(u8); // OK +} + +fn main() {} diff --git a/src/test/compile-fail/no-reuse-move-arc.rs b/src/test/compile-fail/no-reuse-move-arc.rs index 1720b40c83..76c8a44432 100644 --- a/src/test/compile-fail/no-reuse-move-arc.rs +++ b/src/test/compile-fail/no-reuse-move-arc.rs @@ -12,7 +12,7 @@ use std::sync::Arc; use std::thread; fn main() { - let v = vec!(1, 2, 3, 4, 5, 6, 7, 8, 9, 10); + let v = vec![1, 2, 3, 4, 5, 6, 7, 8, 9, 10]; let arc_v = Arc::new(v); thread::spawn(move|| { diff --git a/src/test/compile-fail/no-type-for-node-ice.rs b/src/test/compile-fail/no-type-for-node-ice.rs index aab4db6ead..f049f69e4b 100644 --- a/src/test/compile-fail/no-type-for-node-ice.rs +++ b/src/test/compile-fail/no-type-for-node-ice.rs @@ -11,5 +11,5 @@ // Related issues: #20401, #20506, #20614, #20752, #20829, #20846, #20885, #20886 fn main() { - "".homura[""]; //~ ERROR no field with that name was found + "".homura[""]; //~ no field `homura` on type `&'static str` } diff --git a/src/test/compile-fail/non-copyable-void.rs b/src/test/compile-fail/non-copyable-void.rs index fd245f38a0..6067b71280 100644 --- a/src/test/compile-fail/non-copyable-void.rs +++ b/src/test/compile-fail/non-copyable-void.rs @@ -11,7 +11,7 @@ extern crate libc; fn main() { - let x : *const Vec = &vec!(1,2,3); + let x : *const Vec = &vec![1,2,3]; let y : *const libc::c_void = x as *const libc::c_void; unsafe { let _z = (*y).clone(); diff --git a/src/test/compile-fail/non-exhaustive-match.rs b/src/test/compile-fail/non-exhaustive-match.rs index 017baacc9d..74e728d713 100644 --- a/src/test/compile-fail/non-exhaustive-match.rs +++ b/src/test/compile-fail/non-exhaustive-match.rs @@ -37,20 +37,20 @@ fn main() { (_, t::a) => {} (t::b, t::b) => {} } - let vec = vec!(Some(42), None, Some(21)); + let vec = vec![Some(42), None, Some(21)]; let vec: &[Option] = &vec; match *vec { //~ ERROR non-exhaustive patterns: `[]` not covered [Some(..), None, ref tail..] => {} [Some(..), Some(..), ref tail..] => {} [None] => {} } - let vec = vec!(1); + let vec = vec![1]; let vec: &[isize] = &vec; match *vec { [_, ref tail..] => (), [] => () } - let vec = vec!(0.5f32); + let vec = vec![0.5f32]; let vec: &[f32] = &vec; match *vec { //~ ERROR non-exhaustive patterns: `[_, _, _, _]` not covered [0.1, 0.2, 0.3] => (), @@ -58,7 +58,7 @@ fn main() { [0.1] => (), [] => () } - let vec = vec!(Some(42), None, Some(21)); + let vec = vec![Some(42), None, Some(21)]; let vec: &[Option] = &vec; match *vec { [Some(..), None, ref tail..] => {} diff --git a/src/test/compile-fail/object-lifetime-default-from-rptr-box-error.rs b/src/test/compile-fail/object-lifetime-default-from-rptr-box-error.rs index e351c84c8a..98301ef1a0 100644 --- a/src/test/compile-fail/object-lifetime-default-from-rptr-box-error.rs +++ b/src/test/compile-fail/object-lifetime-default-from-rptr-box-error.rs @@ -11,8 +11,6 @@ // Test that the lifetime from the enclosing `&` is "inherited" // through the `Box` struct. -// pretty-expanded FIXME #23616 - #![allow(dead_code)] trait Test { diff --git a/src/test/compile-fail/object-lifetime-default-from-rptr-struct-error.rs b/src/test/compile-fail/object-lifetime-default-from-rptr-struct-error.rs index 93268559e8..836e4fa114 100644 --- a/src/test/compile-fail/object-lifetime-default-from-rptr-struct-error.rs +++ b/src/test/compile-fail/object-lifetime-default-from-rptr-struct-error.rs @@ -11,8 +11,6 @@ // Test that the lifetime from the enclosing `&` is "inherited" // through the `MyBox` struct. -// pretty-expanded FIXME #23616 - #![allow(dead_code)] #![feature(rustc_error)] diff --git a/src/test/compile-fail/on-unimplemented/multiple-impls.rs b/src/test/compile-fail/on-unimplemented/multiple-impls.rs index cc7c2f4f79..0ad9f21e09 100644 --- a/src/test/compile-fail/on-unimplemented/multiple-impls.rs +++ b/src/test/compile-fail/on-unimplemented/multiple-impls.rs @@ -42,17 +42,17 @@ impl Index> for [i32] { fn main() { Index::index(&[] as &[i32], 2u32); //~^ ERROR E0277 - //~| NOTE not satisfied + //~| NOTE the trait `Index` is not implemented for `[i32]` //~| NOTE trait message //~| NOTE required by Index::index(&[] as &[i32], Foo(2u32)); //~^ ERROR E0277 - //~| NOTE not satisfied + //~| NOTE the trait `Index>` is not implemented for `[i32]` //~| NOTE on impl for Foo //~| NOTE required by Index::index(&[] as &[i32], Bar(2u32)); //~^ ERROR E0277 - //~| NOTE not satisfied + //~| NOTE the trait `Index>` is not implemented for `[i32]` //~| NOTE on impl for Bar //~| NOTE required by } diff --git a/src/test/compile-fail/on-unimplemented/on-impl.rs b/src/test/compile-fail/on-unimplemented/on-impl.rs index c22e48bede..a7c599330a 100644 --- a/src/test/compile-fail/on-unimplemented/on-impl.rs +++ b/src/test/compile-fail/on-unimplemented/on-impl.rs @@ -29,8 +29,9 @@ impl Index for [i32] { #[rustc_error] fn main() { - Index::::index(&[1, 2, 3] as &[i32], 2u32); //~ ERROR E0277 - //~| NOTE not satisfied - //~| NOTE a usize is required - //~| NOTE required by + Index::::index(&[1, 2, 3] as &[i32], 2u32); + //~^ ERROR E0277 + //~| NOTE the trait `Index` is not implemented for `[i32]` + //~| NOTE a usize is required + //~| NOTE required by } diff --git a/src/test/compile-fail/on-unimplemented/on-trait.rs b/src/test/compile-fail/on-unimplemented/on-trait.rs index 9ea2809374..3a789f3fae 100644 --- a/src/test/compile-fail/on-unimplemented/on-trait.rs +++ b/src/test/compile-fail/on-unimplemented/on-trait.rs @@ -30,14 +30,14 @@ fn collect, B: MyFromIterator>(it: I) -> B { } pub fn main() { - let x = vec!(1u8, 2, 3, 4); + let x = vec![1u8, 2, 3, 4]; let y: Option> = collect(x.iter()); // this should give approximately the same error for x.iter().collect() //~^ ERROR //~^^ NOTE a collection of type `std::option::Option>` cannot be built from an iterator over elements of type `&u8` //~^^^ NOTE required by `collect` - //~| NOTE trait `std::option::Option>: MyFromIterator<&u8>` not satisfied + //~| NOTE the trait `MyFromIterator<&u8>` is not implemented for `std::option::Option>` let x: String = foobar(); //~ ERROR //~^ NOTE test error `std::string::String` with `u8` `_` `u32` //~^^ NOTE required by `foobar` - //~| NOTE trait `std::string::String: Foo` not satisfied + //~| NOTE the trait `Foo` is not implemented for `std::string::String` } diff --git a/src/test/compile-fail/on-unimplemented/slice-index.rs b/src/test/compile-fail/on-unimplemented/slice-index.rs index 5c548b5d5b..d528d0e626 100644 --- a/src/test/compile-fail/on-unimplemented/slice-index.rs +++ b/src/test/compile-fail/on-unimplemented/slice-index.rs @@ -17,10 +17,12 @@ use std::ops::Index; #[rustc_error] fn main() { let x = &[1, 2, 3] as &[i32]; - x[1i32]; //~ ERROR E0277 - //~| NOTE trait `[i32]: std::ops::Index` not satisfied - //~| NOTE slice indices are of type `usize` - x[..1i32]; //~ ERROR E0277 - //~| NOTE trait `[i32]: std::ops::Index>` not satisfied - //~| NOTE slice indices are of type `usize` + x[1i32]; + //~^ ERROR E0277 + //~| NOTE the trait `std::ops::Index` is not implemented for `[i32]` + //~| NOTE slice indices are of type `usize` + x[..1i32]; + //~^ ERROR E0277 + //~| NOTE the trait `std::ops::Index>` is not implemented for `[i32]` + //~| NOTE slice indices are of type `usize` } diff --git a/src/test/compile-fail-fulldeps/rustc-macro/require-rustc-macro-crate-type.rs b/src/test/compile-fail/out-of-order-shadowing.rs similarity index 68% rename from src/test/compile-fail-fulldeps/rustc-macro/require-rustc-macro-crate-type.rs rename to src/test/compile-fail/out-of-order-shadowing.rs index cdc50acea9..1fafaf8511 100644 --- a/src/test/compile-fail-fulldeps/rustc-macro/require-rustc-macro-crate-type.rs +++ b/src/test/compile-fail/out-of-order-shadowing.rs @@ -8,14 +8,14 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -#![feature(rustc_macro)] +// aux-build:define_macro.rs +// error-pattern: `bar` is already in scope -extern crate rustc_macro; +macro_rules! bar { () => {} } +define_macro!(bar); +bar!(); -#[rustc_macro_derive(Foo)] -//~^ ERROR: only usable with crates of the `rustc-macro` crate type -pub fn foo(a: rustc_macro::TokenStream) -> rustc_macro::TokenStream { - a -} +macro_rules! m { () => { #[macro_use] extern crate define_macro; } } +m!(); fn main() {} diff --git a/src/test/compile-fail/pat-shadow-in-nested-binding.rs b/src/test/compile-fail/pat-shadow-in-nested-binding.rs index f1683e51c6..3dbe08f190 100644 --- a/src/test/compile-fail/pat-shadow-in-nested-binding.rs +++ b/src/test/compile-fail/pat-shadow-in-nested-binding.rs @@ -11,5 +11,5 @@ struct foo(usize); fn main() { - let (foo, _) = (2, 3); //~ ERROR let bindings cannot shadow structs + let (foo, _) = (2, 3); //~ ERROR let bindings cannot shadow tuple structs } diff --git a/src/test/compile-fail/pat-tuple-bad-type.rs b/src/test/compile-fail/pat-tuple-bad-type.rs index 0d50a30dd0..fd4ab5d253 100644 --- a/src/test/compile-fail/pat-tuple-bad-type.rs +++ b/src/test/compile-fail/pat-tuple-bad-type.rs @@ -8,8 +8,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -#![feature(dotdot_in_tuple_patterns)] - fn main() { let x; diff --git a/src/test/compile-fail/pat-tuple-overfield.rs b/src/test/compile-fail/pat-tuple-overfield.rs index 034ef4a72e..851fa5c5be 100644 --- a/src/test/compile-fail/pat-tuple-overfield.rs +++ b/src/test/compile-fail/pat-tuple-overfield.rs @@ -8,8 +8,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -#![feature(dotdot_in_tuple_patterns)] - struct S(u8, u8, u8); fn main() { @@ -20,9 +18,9 @@ fn main() { } match S(1, 2, 3) { S(1, 2, 3, 4) => {} - //~^ ERROR this pattern has 4 fields, but the corresponding struct has 3 fields + //~^ ERROR this pattern has 4 fields, but the corresponding tuple struct has 3 fields S(1, 2, .., 3, 4) => {} - //~^ ERROR this pattern has 4 fields, but the corresponding struct has 3 fields + //~^ ERROR this pattern has 4 fields, but the corresponding tuple struct has 3 fields _ => {} } } diff --git a/src/test/compile-fail/pattern-error-continue.rs b/src/test/compile-fail/pattern-error-continue.rs index 507012e8c5..e63b84594a 100644 --- a/src/test/compile-fail/pattern-error-continue.rs +++ b/src/test/compile-fail/pattern-error-continue.rs @@ -25,7 +25,7 @@ fn f(_c: char) {} fn main() { match A::B(1, 2) { A::B(_, _, _) => (), //~ ERROR this pattern has 3 fields, but - A::D(_) => (), //~ ERROR `A::D` does not name a tuple variant or a tuple struct + A::D(_) => (), //~ ERROR expected tuple struct/variant, found unit variant `A::D` _ => () } match 'c' { diff --git a/src/test/compile-fail/qualified-path-params.rs b/src/test/compile-fail/qualified-path-params.rs index 9034e24a6f..82b0536a64 100644 --- a/src/test/compile-fail/qualified-path-params.rs +++ b/src/test/compile-fail/qualified-path-params.rs @@ -28,7 +28,7 @@ impl S { fn main() { match 10 { ::A::f:: => {} - //~^ ERROR `Tr::A::f` does not name a unit variant, unit struct or a constant + //~^ ERROR expected unit struct/variant or constant, found method `Tr::A::f` 0 ... ::A::f:: => {} //~ ERROR only char and numeric types are allowed in range } } diff --git a/src/test/compile-fail/regions-bound-missing-bound-in-impl.rs b/src/test/compile-fail/regions-bound-missing-bound-in-impl.rs index 6e60a373d9..1d4ffe0690 100644 --- a/src/test/compile-fail/regions-bound-missing-bound-in-impl.rs +++ b/src/test/compile-fail/regions-bound-missing-bound-in-impl.rs @@ -52,7 +52,7 @@ impl<'a, 't> Foo<'a, 't> for &'a isize { } fn another_bound<'x: 't>(self, x: Inv<'x>, y: Inv<'t>) { - //~^ ERROR lifetime bound not satisfied + //~^ ERROR E0276 } } diff --git a/src/test/compile-fail/resolve-inconsistent-names.rs b/src/test/compile-fail/resolve-inconsistent-names.rs index f7f3acd37d..1e2541502a 100644 --- a/src/test/compile-fail/resolve-inconsistent-names.rs +++ b/src/test/compile-fail/resolve-inconsistent-names.rs @@ -11,7 +11,9 @@ fn main() { let y = 1; match y { - a | b => {} //~ ERROR variable `a` from pattern #1 is not bound in pattern #2 - //~^ ERROR variable `b` from pattern #2 is not bound in pattern #1 + a | b => {} //~ ERROR variable `a` from pattern #1 is not bound in pattern #2 + //~^ ERROR variable `b` from pattern #2 is not bound in pattern #1 + //~| NOTE pattern doesn't bind `a` + //~| NOTE pattern doesn't bind `b` } } diff --git a/src/test/compile-fail/self-vs-path-ambiguity.rs b/src/test/compile-fail/self-vs-path-ambiguity.rs new file mode 100644 index 0000000000..9753014e78 --- /dev/null +++ b/src/test/compile-fail/self-vs-path-ambiguity.rs @@ -0,0 +1,23 @@ +// Copyright 2016 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +// Check that `self::foo` is parsed as a general pattern and not a self argument. + +struct S; + +impl S { + fn f(self::S: S) {} + fn g(&self::S: &S) {} + fn h(&mut self::S: &mut S) {} + fn i(&'a self::S: &S) {} //~ ERROR unexpected lifetime `'a` in pattern + //~^ ERROR expected one of `)` or `mut`, found `'a` +} + +fn main() {} diff --git a/src/test/compile-fail/self_type_keyword-2.rs b/src/test/compile-fail/self_type_keyword-2.rs index 613f54eb33..118d3d8a0b 100644 --- a/src/test/compile-fail/self_type_keyword-2.rs +++ b/src/test/compile-fail/self_type_keyword-2.rs @@ -10,4 +10,14 @@ use self::Self as Foo; //~ ERROR unresolved import `self::Self` -pub fn main() {} +pub fn main() { + let Self = 5; + //~^ ERROR unresolved unit struct/variant or constant `Self` + + match 15 { + Self => (), + //~^ ERROR unresolved unit struct/variant or constant `Self` + Foo { x: Self } => (), + //~^ ERROR unresolved unit struct/variant or constant `Self` + } +} diff --git a/src/test/compile-fail/self_type_keyword.rs b/src/test/compile-fail/self_type_keyword.rs index 911606ef01..db6bcc611b 100644 --- a/src/test/compile-fail/self_type_keyword.rs +++ b/src/test/compile-fail/self_type_keyword.rs @@ -17,12 +17,7 @@ struct Bar<'Self>; //~^ ERROR lifetimes cannot use keyword names pub fn main() { - let Self = 5; - //~^ ERROR expected identifier, found keyword `Self` - match 15 { - Self => (), - //~^ ERROR expected identifier, found keyword `Self` ref Self => (), //~^ ERROR expected identifier, found keyword `Self` mut Self => (), @@ -31,18 +26,22 @@ pub fn main() { //~^ ERROR expected identifier, found keyword `Self` Self!() => (), //~^ ERROR macro undefined: 'Self!' - Foo { x: Self } => (), - //~^ ERROR expected identifier, found keyword `Self` Foo { Self } => (), //~^ ERROR expected identifier, found keyword `Self` } } -use std::option::Option as Self; -//~^ ERROR expected identifier, found keyword `Self` +mod m1 { + extern crate core as Self; + //~^ ERROR expected identifier, found keyword `Self` +} -extern crate Self; -//~^ ERROR expected identifier, found keyword `Self` +mod m2 { + use std::option::Option as Self; + //~^ ERROR expected identifier, found keyword `Self` +} -trait Self {} -//~^ ERROR expected identifier, found keyword `Self` +mod m3 { + trait Self {} + //~^ ERROR expected identifier, found keyword `Self` +} diff --git a/src/test/compile-fail/struct-fields-shorthand-unresolved.rs b/src/test/compile-fail/struct-fields-shorthand-unresolved.rs new file mode 100644 index 0000000000..50a43f4a27 --- /dev/null +++ b/src/test/compile-fail/struct-fields-shorthand-unresolved.rs @@ -0,0 +1,24 @@ +// 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(field_init_shorthand)] + +struct Foo { + x: i32, + y: i32 +} + +fn main() { + let x = 0; + let foo = Foo { + x, + y //~ ERROR unresolved name `y` + }; +} diff --git a/src/test/compile-fail/struct-fields-shorthand.rs b/src/test/compile-fail/struct-fields-shorthand.rs new file mode 100644 index 0000000000..f764322cad --- /dev/null +++ b/src/test/compile-fail/struct-fields-shorthand.rs @@ -0,0 +1,24 @@ +// 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(field_init_shorthand)] + +struct Foo { + x: i32, + y: i32 +} + +fn main() { + let (x, y, z) = (0, 1, 2); + let foo = Foo { + x, y, z //~ ERROR struct `Foo` has no field named `z` + }; +} + diff --git a/src/test/compile-fail/struct-fields-typo.rs b/src/test/compile-fail/struct-fields-typo.rs index c897dc5520..0e30c1e86e 100644 --- a/src/test/compile-fail/struct-fields-typo.rs +++ b/src/test/compile-fail/struct-fields-typo.rs @@ -18,7 +18,7 @@ fn main() { foo: 0, bar: 0.5, }; - let x = foo.baa;//~ ERROR attempted access of field `baa` on type `BuildData` - //~^ HELP did you mean `bar`? + let x = foo.baa;//~ no field `baa` on type `BuildData` + //~^ did you mean `bar`? println!("{}", x); } diff --git a/src/test/compile-fail/struct-pat-derived-error.rs b/src/test/compile-fail/struct-pat-derived-error.rs index 4b65292340..f525ec3737 100644 --- a/src/test/compile-fail/struct-pat-derived-error.rs +++ b/src/test/compile-fail/struct-pat-derived-error.rs @@ -15,7 +15,7 @@ struct a { impl a { fn foo(&self) { - let a { x, y } = self.d; //~ ERROR attempted access of field `d` + let a { x, y } = self.d; //~ ERROR no field `d` on type `&a` //~^ ERROR struct `a` does not have a field named `x` //~^^ ERROR struct `a` does not have a field named `y` //~^^^ ERROR pattern does not mention field `b` diff --git a/src/test/compile-fail/struct-path-alias-bounds.rs b/src/test/compile-fail/struct-path-alias-bounds.rs new file mode 100644 index 0000000000..1b6e51e370 --- /dev/null +++ b/src/test/compile-fail/struct-path-alias-bounds.rs @@ -0,0 +1,21 @@ +// Copyright 2016 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +// issue #36286 + +struct S { a: T } + +struct NoClone; +type A = S; + +fn main() { + let s = A { a: NoClone }; + //~^ ERROR the trait bound `NoClone: std::clone::Clone` is not satisfied +} diff --git a/src/test/compile-fail/struct-path-associated-type.rs b/src/test/compile-fail/struct-path-associated-type.rs new file mode 100644 index 0000000000..ecaf269fcb --- /dev/null +++ b/src/test/compile-fail/struct-path-associated-type.rs @@ -0,0 +1,50 @@ +// Copyright 2016 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +#![feature(more_struct_aliases)] + +struct S; + +trait Tr { + type A; +} + +impl Tr for S { + type A = S; +} + +fn f() { + let s = T::A {}; + //~^ ERROR expected struct, variant or union type, found associated type + let z = T::A:: {}; + //~^ ERROR expected struct, variant or union type, found associated type + //~| ERROR type parameters are not allowed on this type + match S { + T::A {} => {} + //~^ ERROR expected struct, variant or union type, found associated type + } +} + +fn g>() { + let s = T::A {}; // OK + let z = T::A:: {}; //~ ERROR type parameters are not allowed on this type + match S { + T::A {} => {} // OK + } +} + +fn main() { + let s = S::A {}; //~ ERROR ambiguous associated type + let z = S::A:: {}; //~ ERROR ambiguous associated type + //~^ ERROR type parameters are not allowed on this type + match S { + S::A {} => {} //~ ERROR ambiguous associated type + } +} diff --git a/src/test/compile-fail/struct-path-self-feature-gate.rs b/src/test/compile-fail/struct-path-self-feature-gate.rs new file mode 100644 index 0000000000..a2050182a7 --- /dev/null +++ b/src/test/compile-fail/struct-path-self-feature-gate.rs @@ -0,0 +1,29 @@ +// Copyright 2016 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +struct S; + +trait Tr { + type A; +} + +fn f>() { + let _ = T::A {}; + //~^ ERROR `Self` and associated types in struct expressions and patterns are unstable +} + +impl S { + fn f() { + let _ = Self {}; + //~^ ERROR `Self` and associated types in struct expressions and patterns are unstable + } +} + +fn main() {} diff --git a/src/test/compile-fail/struct-path-self-type-mismatch.rs b/src/test/compile-fail/struct-path-self-type-mismatch.rs new file mode 100644 index 0000000000..8352bd6751 --- /dev/null +++ b/src/test/compile-fail/struct-path-self-type-mismatch.rs @@ -0,0 +1,40 @@ +// Copyright 2016 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +#![feature(more_struct_aliases)] + +struct Foo { inner: A } + +trait Bar { fn bar(); } + +impl Bar for Foo { + fn bar() { + Self { inner: 1.5f32 }; //~ ERROR mismatched types + //~^ NOTE expected i32, found f32 + } +} + +impl Foo { + fn new(u: U) -> Foo { + Self { + //~^ ERROR mismatched types + //~| expected type parameter, found a different type parameter + //~| expected type `Foo` + //~| found type `Foo` + inner: u + //~^ ERROR mismatched types + //~| expected type parameter, found a different type parameter + //~| expected type `T` + //~| found type `U` + } + } +} + +fn main() {} diff --git a/src/test/compile-fail/struct-path-self.rs b/src/test/compile-fail/struct-path-self.rs new file mode 100644 index 0000000000..aeac199227 --- /dev/null +++ b/src/test/compile-fail/struct-path-self.rs @@ -0,0 +1,49 @@ +// Copyright 2016 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +#![feature(more_struct_aliases)] + +struct S; + +trait Tr { + fn f() { + let s = Self {}; + //~^ ERROR expected struct, variant or union type, found Self + let z = Self:: {}; + //~^ ERROR expected struct, variant or union type, found Self + //~| ERROR type parameters are not allowed on this type + match s { + Self { .. } => {} + //~^ ERROR expected struct, variant or union type, found Self + } + } +} + +impl Tr for S { + fn f() { + let s = Self {}; // OK + let z = Self:: {}; //~ ERROR type parameters are not allowed on this type + match s { + Self { .. } => {} // OK + } + } +} + +impl S { + fn g() { + let s = Self {}; // OK + let z = Self:: {}; //~ ERROR type parameters are not allowed on this type + match s { + Self { .. } => {} // OK + } + } +} + +fn main() {} diff --git a/src/test/compile-fail/trait-as-struct-constructor.rs b/src/test/compile-fail/trait-as-struct-constructor.rs index c78eebddbf..49d58580da 100644 --- a/src/test/compile-fail/trait-as-struct-constructor.rs +++ b/src/test/compile-fail/trait-as-struct-constructor.rs @@ -12,6 +12,5 @@ trait TraitNotAStruct {} fn main() { TraitNotAStruct{ value: 0 }; - //~^ ERROR: `TraitNotAStruct` does not name a struct or a struct variant [E0071] - //~| NOTE not a struct + //~^ ERROR expected struct, variant or union type, found trait `TraitNotAStruct` } diff --git a/src/test/compile-fail/trait-suggest-where-clause.rs b/src/test/compile-fail/trait-suggest-where-clause.rs index d15e3536d6..7530d8890b 100644 --- a/src/test/compile-fail/trait-suggest-where-clause.rs +++ b/src/test/compile-fail/trait-suggest-where-clause.rs @@ -16,13 +16,13 @@ fn check() { // suggest a where-clause, if needed mem::size_of::(); //~^ ERROR `U: std::marker::Sized` is not satisfied - //~| NOTE trait `U: std::marker::Sized` not satisfied + //~| NOTE the trait `std::marker::Sized` is not implemented for `U` //~| HELP consider adding a `where U: std::marker::Sized` bound //~| NOTE required by `std::mem::size_of` mem::size_of::>(); //~^ ERROR `U: std::marker::Sized` is not satisfied - //~| NOTE trait `U: std::marker::Sized` not satisfied + //~| NOTE the trait `std::marker::Sized` is not implemented for `U` //~| HELP consider adding a `where U: std::marker::Sized` bound //~| NOTE required because it appears within the type `Misc` //~| NOTE required by `std::mem::size_of` @@ -31,13 +31,13 @@ fn check() { >::from; //~^ ERROR `u64: std::convert::From` is not satisfied - //~| NOTE trait `u64: std::convert::From` not satisfied + //~| NOTE the trait `std::convert::From` is not implemented for `u64` //~| HELP consider adding a `where u64: std::convert::From` bound //~| NOTE required by `std::convert::From::from` ::Item>>::from; //~^ ERROR `u64: std::convert::From<::Item>` is not satisfied - //~| NOTE trait `u64: std::convert::From<::Item>` not satisfied + //~| NOTE the trait `std::convert::From<::Item>` is not implemented //~| HELP consider adding a `where u64: //~| NOTE required by `std::convert::From::from` @@ -45,20 +45,20 @@ fn check() { as From>::from; //~^ ERROR `Misc<_>: std::convert::From` is not satisfied - //~| NOTE trait `Misc<_>: std::convert::From` not satisfied + //~| NOTE the trait `std::convert::From` is not implemented for `Misc<_>` //~| NOTE required by `std::convert::From::from` // ... and also not if the error is not related to the type mem::size_of::<[T]>(); //~^ ERROR `[T]: std::marker::Sized` is not satisfied - //~| NOTE `[T]: std::marker::Sized` not satisfied + //~| NOTE the trait `std::marker::Sized` is not implemented for `[T]` //~| NOTE `[T]` does not have a constant size //~| NOTE required by `std::mem::size_of` mem::size_of::<[&U]>(); //~^ ERROR `[&U]: std::marker::Sized` is not satisfied - //~| NOTE `[&U]: std::marker::Sized` not satisfied + //~| NOTE the trait `std::marker::Sized` is not implemented for `[&U]` //~| NOTE `[&U]` does not have a constant size //~| NOTE required by `std::mem::size_of` } diff --git a/src/test/compile-fail/typeck_type_placeholder_lifetime_1.rs b/src/test/compile-fail/typeck_type_placeholder_lifetime_1.rs index f60d925a74..f40445a030 100644 --- a/src/test/compile-fail/typeck_type_placeholder_lifetime_1.rs +++ b/src/test/compile-fail/typeck_type_placeholder_lifetime_1.rs @@ -18,5 +18,5 @@ struct Foo<'a, T:'a> { pub fn main() { let c: Foo<_, _> = Foo { r: &5 }; //~^ ERROR E0244 - //~| NOTE expected 1 type arguments, found 2 + //~| NOTE expected 1 type argument, found 2 } diff --git a/src/test/compile-fail/typeck_type_placeholder_lifetime_2.rs b/src/test/compile-fail/typeck_type_placeholder_lifetime_2.rs index ec2675ece7..47898690fc 100644 --- a/src/test/compile-fail/typeck_type_placeholder_lifetime_2.rs +++ b/src/test/compile-fail/typeck_type_placeholder_lifetime_2.rs @@ -18,5 +18,5 @@ struct Foo<'a, T:'a> { pub fn main() { let c: Foo<_, usize> = Foo { r: &5 }; //~^ ERROR E0244 - //~| NOTE expected 1 type arguments, found 2 + //~| NOTE expected 1 type argument, found 2 } 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 1209757610..50f4f3b98b 100644 --- a/src/test/compile-fail/unboxed-closure-sugar-wrong-trait.rs +++ b/src/test/compile-fail/unboxed-closure-sugar-wrong-trait.rs @@ -15,6 +15,7 @@ trait Trait {} fn f isize>(x: F) {} //~^ ERROR E0244 //~| NOTE expected no type arguments, found 1 -//~| ERROR associated type `Output` not found +//~| ERROR E0220 +//~| NOTE associated type `Output` not found fn main() {} diff --git a/src/test/compile-fail/unboxed-closures-failed-recursive-fn-2.rs b/src/test/compile-fail/unboxed-closures-failed-recursive-fn-2.rs index f40c8fc747..12b48b2a6c 100644 --- a/src/test/compile-fail/unboxed-closures-failed-recursive-fn-2.rs +++ b/src/test/compile-fail/unboxed-closures-failed-recursive-fn-2.rs @@ -16,7 +16,7 @@ fn a() { let mut closure0 = None; - let vec = vec!(1, 2, 3); + let vec = vec![1, 2, 3]; loop { { diff --git a/src/test/compile-fail/unboxed-closures-move-upvar-from-non-once-ref-closure.rs b/src/test/compile-fail/unboxed-closures-move-upvar-from-non-once-ref-closure.rs index e66610c149..cd9f1636c3 100644 --- a/src/test/compile-fail/unboxed-closures-move-upvar-from-non-once-ref-closure.rs +++ b/src/test/compile-fail/unboxed-closures-move-upvar-from-non-once-ref-closure.rs @@ -16,7 +16,7 @@ fn call(f: F) where F : Fn() { } fn main() { - let y = vec!(format!("World")); + let y = vec![format!("World")]; call(|| { y.into_iter(); //~^ ERROR cannot move out of captured outer variable in an `Fn` closure diff --git a/src/test/compile-fail/union/union-suggest-field.rs b/src/test/compile-fail/union/union-suggest-field.rs index ce421428d8..3c355989b8 100644 --- a/src/test/compile-fail/union/union-suggest-field.rs +++ b/src/test/compile-fail/union/union-suggest-field.rs @@ -22,8 +22,8 @@ fn main() { let u = U { principle: 0 }; //~^ ERROR union `U` has no field named `principle` //~| NOTE field does not exist - did you mean `principal`? - let w = u.principial; //~ ERROR attempted access of field `principial` on type `U` - //~^ HELP did you mean `principal`? + let w = u.principial; //~ ERROR no field `principial` on type `U` + //~^ did you mean `principal`? let y = u.calculate; //~ ERROR attempted to take value of method `calculate` on type `U` //~^ HELP maybe a `()` to call it is missing? diff --git a/src/test/compile-fail/unresolved-import.rs b/src/test/compile-fail/unresolved-import.rs index 0a9a437569..47490af0ff 100644 --- a/src/test/compile-fail/unresolved-import.rs +++ b/src/test/compile-fail/unresolved-import.rs @@ -11,7 +11,7 @@ // ignore-tidy-linelength use foo::bar; //~ ERROR unresolved import `foo::bar` [E0432] - //~^ Maybe a missing `extern crate foo`? + //~^ Maybe a missing `extern crate foo;`? use bar::Baz as x; //~ ERROR unresolved import `bar::Baz` [E0432] //~^ no `Baz` in `bar`. Did you mean to use `Bar`? diff --git a/src/test/compile-fail/unsafe-fn-autoderef.rs b/src/test/compile-fail/unsafe-fn-autoderef.rs index 97a7bf1471..15b304c69b 100644 --- a/src/test/compile-fail/unsafe-fn-autoderef.rs +++ b/src/test/compile-fail/unsafe-fn-autoderef.rs @@ -26,7 +26,7 @@ fn f(p: *const Rec) -> isize { // are prohibited by various checks, such as that the enum is // instantiable and so forth). - return p.f; //~ ERROR attempted access of field `f` on type `*const Rec` + return p.f; //~ ERROR no field `f` on type `*const Rec` } fn main() { diff --git a/src/test/compile-fail/unsized-enum.rs b/src/test/compile-fail/unsized-enum.rs index 61b2b01b35..5d791215f3 100644 --- a/src/test/compile-fail/unsized-enum.rs +++ b/src/test/compile-fail/unsized-enum.rs @@ -19,11 +19,4 @@ fn foo2() { not_sized::>() } // // Not OK: `T` is not sized. -enum Bar { BarSome(U), BarNone } -fn bar1() { not_sized::>() } -fn bar2() { is_sized::>() } -//~^ ERROR `T: std::marker::Sized` is not satisfied -// -// Not OK: `Bar` is not sized, but it should be. - fn main() { } diff --git a/src/test/compile-fail/unsized-enum2.rs b/src/test/compile-fail/unsized-enum2.rs new file mode 100644 index 0000000000..95fc3243fb --- /dev/null +++ b/src/test/compile-fail/unsized-enum2.rs @@ -0,0 +1,68 @@ +// Copyright 206 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::ops::Deref; + +// Due to aggressive error message deduplication, we require 20 *different* +// unsized types (even Path and [u8] are considered the "same"). + +trait Foo {} +trait Bar {} +trait FooBar {} +trait BarFoo {} + +trait PathHelper1 {} +trait PathHelper2 {} +trait PathHelper3 {} +trait PathHelper4 {} + +struct Path1(PathHelper1); +struct Path2(PathHelper2); +struct Path3(PathHelper3); +struct Path4(PathHelper4); + +enum E { + // parameter + VA(W), //~ ERROR `W: std::marker::Sized` is not satisfied + VB{x: X}, //~ ERROR `X: std::marker::Sized` is not satisfied + VC(isize, Y), //~ ERROR `Y: std::marker::Sized` is not satisfied + VD{u: isize, x: Z}, //~ ERROR `Z: std::marker::Sized` is not satisfied + + // slice / str + VE([u8]), //~ ERROR `[u8]: std::marker::Sized` is not satisfied + VF{x: str}, //~ ERROR `str: std::marker::Sized` is not satisfied + VG(isize, [f32]), //~ ERROR `[f32]: std::marker::Sized` is not satisfied + VH{u: isize, x: [u32]}, //~ ERROR `[u32]: std::marker::Sized` is not satisfied + + // unsized struct + VI(Path1), //~ ERROR `PathHelper1 + 'static: std::marker::Sized` is not satisfied + VJ{x: Path2}, //~ ERROR `PathHelper2 + 'static: std::marker::Sized` is not satisfied + VK(isize, Path3), //~ ERROR `PathHelper3 + 'static: std::marker::Sized` is not satisfied + VL{u: isize, x: Path4}, //~ ERROR `PathHelper4 + 'static: std::marker::Sized` is not satisfied + + // plain trait + VM(Foo), //~ ERROR `Foo + 'static: std::marker::Sized` is not satisfied + VN{x: Bar}, //~ ERROR `Bar + 'static: std::marker::Sized` is not satisfied + VO(isize, FooBar), //~ ERROR `FooBar + 'static: std::marker::Sized` is not satisfied + VP{u: isize, x: BarFoo}, //~ ERROR `BarFoo + 'static: std::marker::Sized` is not satisfied + + // projected + VQ(<&'static [i8] as Deref>::Target), //~ ERROR `[i8]: std::marker::Sized` is not satisfied + VR{x: <&'static [char] as Deref>::Target}, + //~^ ERROR `[char]: std::marker::Sized` is not satisfied + VS(isize, <&'static [f64] as Deref>::Target), + //~^ ERROR `[f64]: std::marker::Sized` is not satisfied + VT{u: isize, x: <&'static [i32] as Deref>::Target}, + //~^ ERROR `[i32]: std::marker::Sized` is not satisfied +} + + +fn main() { } + diff --git a/src/test/compile-fail/unsized3.rs b/src/test/compile-fail/unsized3.rs index f88165c02e..9b6ccf22c8 100644 --- a/src/test/compile-fail/unsized3.rs +++ b/src/test/compile-fail/unsized3.rs @@ -31,19 +31,8 @@ fn f3(x: &X) { fn f4(x: &X) { } -// Test with unsized enum. -enum E { - V(X), -} - fn f5(x: &Y) {} fn f6(x: &X) {} -fn f7(x1: &E, x2: &E) { - f5(x1); - //~^ ERROR `X: std::marker::Sized` is not satisfied - f6(x2); // ok -} - // Test with unsized struct. struct S { @@ -57,13 +46,13 @@ fn f8(x1: &S, x2: &S) { } // Test some tuples. -fn f9(x1: Box>, x2: Box>) { +fn f9(x1: Box>) { f5(&(*x1, 34)); //~^ ERROR `X: std::marker::Sized` is not satisfied } -fn f10(x1: Box>, x2: Box>) { - f5(&(32, *x2)); +fn f10(x1: Box>) { + f5(&(32, *x1)); //~^ ERROR `X: std::marker::Sized` is not satisfied } diff --git a/src/test/compile-fail/use-super-global-path.rs b/src/test/compile-fail/use-super-global-path.rs index 1d0d60a775..3fa0712fb4 100644 --- a/src/test/compile-fail/use-super-global-path.rs +++ b/src/test/compile-fail/use-super-global-path.rs @@ -8,22 +8,20 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -#![feature(rustc_attrs)] -#![allow(unused_imports, dead_code)] +#![allow(unused)] struct S; struct Z; mod foo { - use ::super::{S, Z}; //~ WARN global paths cannot start with `super` + use ::super::{S, Z}; //~ ERROR global paths cannot start with `super` //~^ WARN this was previously accepted by the compiler but is being phased out pub fn g() { - use ::super::main; //~ WARN global paths cannot start with `super` + use ::super::main; //~ ERROR global paths cannot start with `super` //~^ WARN this was previously accepted by the compiler but is being phased out main(); } } -#[rustc_error] -fn main() { foo::g(); } //~ ERROR compilation successful +fn main() { foo::g(); } diff --git a/src/test/compile-fail/variadic-ffi-2.rs b/src/test/compile-fail/variadic-ffi-2.rs index 1d519c978a..afcad9d8f9 100644 --- a/src/test/compile-fail/variadic-ffi-2.rs +++ b/src/test/compile-fail/variadic-ffi-2.rs @@ -8,7 +8,7 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -fn baz(f: extern "stdcall" fn(usize, ...)) { +fn baz(f: extern "cdecl" fn(usize, ...)) { //~^ ERROR: variadic function must have C calling convention f(22, 44); } diff --git a/src/test/compile-fail/variadic-ffi.rs b/src/test/compile-fail/variadic-ffi.rs index 1294217849..af2b552e20 100644 --- a/src/test/compile-fail/variadic-ffi.rs +++ b/src/test/compile-fail/variadic-ffi.rs @@ -8,7 +8,7 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -extern "stdcall" { +extern "cdecl" { fn printf(_: *const u8, ...); //~ ERROR: variadic function must have C calling convention } diff --git a/src/test/compile-fail/variance-trait-matching.rs b/src/test/compile-fail/variance-trait-matching.rs index 49dc1e68c2..2d78940ce4 100644 --- a/src/test/compile-fail/variance-trait-matching.rs +++ b/src/test/compile-fail/variance-trait-matching.rs @@ -8,8 +8,6 @@ // 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 diff --git a/src/test/compile-fail/vec-macro-with-comma-only.rs b/src/test/compile-fail/vec-macro-with-comma-only.rs index 346cf1ec55..96f58666fd 100644 --- a/src/test/compile-fail/vec-macro-with-comma-only.rs +++ b/src/test/compile-fail/vec-macro-with-comma-only.rs @@ -9,5 +9,5 @@ // except according to those terms. pub fn main() { - vec!(,); //~ ERROR expected expression, found `,` + vec![,]; //~ ERROR expected expression, found `,` } diff --git a/src/test/compile-fail/vec-mut-iter-borrow.rs b/src/test/compile-fail/vec-mut-iter-borrow.rs index 023ef72c45..571634e399 100644 --- a/src/test/compile-fail/vec-mut-iter-borrow.rs +++ b/src/test/compile-fail/vec-mut-iter-borrow.rs @@ -9,7 +9,7 @@ // except according to those terms. fn main() { - let mut xs: Vec = vec!(); + let mut xs: Vec = vec![]; for x in &mut xs { xs.push(1) //~ ERROR cannot borrow `xs` diff --git a/src/test/compile-fail/vec-res-add.rs b/src/test/compile-fail/vec-res-add.rs index cf64486c9c..27f6fc5116 100644 --- a/src/test/compile-fail/vec-res-add.rs +++ b/src/test/compile-fail/vec-res-add.rs @@ -21,8 +21,8 @@ impl Drop for r { fn main() { // This can't make sense as it would copy the classes - let i = vec!(r(0)); - let j = vec!(r(1)); + let i = vec![r(0)]; + let j = vec![r(1)]; let k = i + j; //~^ ERROR binary operation `+` cannot be applied to type println!("{:?}", j); diff --git a/src/test/compile-fail/windows-subsystem-gated.rs b/src/test/compile-fail/windows-subsystem-gated.rs new file mode 100644 index 0000000000..4b563e78e5 --- /dev/null +++ b/src/test/compile-fail/windows-subsystem-gated.rs @@ -0,0 +1,14 @@ +// Copyright 2016 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +#![windows_subsystem = "console"] +//~^ ERROR: the windows subsystem attribute is currently unstable + +fn main() {} diff --git a/src/test/compile-fail/windows-subsystem-invalid.rs b/src/test/compile-fail/windows-subsystem-invalid.rs new file mode 100644 index 0000000000..e000344071 --- /dev/null +++ b/src/test/compile-fail/windows-subsystem-invalid.rs @@ -0,0 +1,16 @@ +// Copyright 2016 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +// error-pattern: invalid windows subsystem `wrong`, only `windows` and `console` are allowed + +#![feature(windows_subsystem)] +#![windows_subsystem = "wrong"] + +fn main() {} diff --git a/src/test/compile-fail/writing-to-immutable-vec.rs b/src/test/compile-fail/writing-to-immutable-vec.rs index 09c9439b46..f289b85992 100644 --- a/src/test/compile-fail/writing-to-immutable-vec.rs +++ b/src/test/compile-fail/writing-to-immutable-vec.rs @@ -10,6 +10,6 @@ fn main() { - let v: Vec = vec!(1, 2, 3); + let v: Vec = vec![1, 2, 3]; v[1] = 4; //~ ERROR cannot borrow immutable local variable `v` as mutable } diff --git a/src/test/compile-fail/xcrate-private-by-default.rs b/src/test/compile-fail/xcrate-private-by-default.rs index 3bd4c78062..7dd4d97094 100644 --- a/src/test/compile-fail/xcrate-private-by-default.rs +++ b/src/test/compile-fail/xcrate-private-by-default.rs @@ -39,7 +39,7 @@ fn main() { foo::(); //~^ ERROR: enum `m` is private foo::(); - //~^ ERROR: type `n` is private + //~^ ERROR: type alias `n` is private // public items in a private mod should be inaccessible static_priv_by_default::foo::a; diff --git a/src/test/debuginfo/associated-types.rs b/src/test/debuginfo/associated-types.rs index ebaad663bb..ccd9402271 100644 --- a/src/test/debuginfo/associated-types.rs +++ b/src/test/debuginfo/associated-types.rs @@ -16,7 +16,8 @@ // gdb-command:run // gdb-command:print arg -// gdb-check:$1 = {b = -1, b1 = 0} +// gdbg-check:$1 = {b = -1, b1 = 0} +// gdbr-check:$1 = associated_types::Struct {b: -1, b1: 0} // gdb-command:continue // gdb-command:print inferred @@ -30,7 +31,8 @@ // gdb-command:continue // gdb-command:print arg -// gdb-check:$5 = {__0 = 4, __1 = 5} +// gdbg-check:$5 = {__0 = 4, __1 = 5} +// gdbr-check:$5 = (4, 5) // gdb-command:continue // gdb-command:print a diff --git a/src/test/debuginfo/basic-types-globals-metadata.rs b/src/test/debuginfo/basic-types-globals-metadata.rs index 8818063ddf..fe687dabe9 100644 --- a/src/test/debuginfo/basic-types-globals-metadata.rs +++ b/src/test/debuginfo/basic-types-globals-metadata.rs @@ -12,33 +12,47 @@ // compile-flags:-g // gdb-command:run -// gdb-command:whatis 'basic_types_globals_metadata::B' +// gdbg-command:whatis 'basic_types_globals_metadata::B' +// gdbr-command:whatis basic_types_globals_metadata::B // gdb-check:type = bool -// gdb-command:whatis 'basic_types_globals_metadata::I' +// gdbg-command:whatis 'basic_types_globals_metadata::I' +// gdbr-command:whatis basic_types_globals_metadata::I // gdb-check:type = isize -// gdb-command:whatis 'basic_types_globals_metadata::C' +// gdbg-command:whatis 'basic_types_globals_metadata::C' +// gdbr-command:whatis basic_types_globals_metadata::C // gdb-check:type = char -// gdb-command:whatis 'basic_types_globals_metadata::I8' +// gdbg-command:whatis 'basic_types_globals_metadata::I8' +// gdbr-command:whatis basic_types_globals_metadata::I8 // gdb-check:type = i8 -// gdb-command:whatis 'basic_types_globals_metadata::I16' +// gdbg-command:whatis 'basic_types_globals_metadata::I16' +// gdbr-command:whatis basic_types_globals_metadata::I16 // gdb-check:type = i16 -// gdb-command:whatis 'basic_types_globals_metadata::I32' +// gdbg-command:whatis 'basic_types_globals_metadata::I32' +// gdbr-command:whatis basic_types_globals_metadata::I32 // gdb-check:type = i32 -// gdb-command:whatis 'basic_types_globals_metadata::I64' +// gdbg-command:whatis 'basic_types_globals_metadata::I64' +// gdbr-command:whatis basic_types_globals_metadata::I64 // gdb-check:type = i64 -// gdb-command:whatis 'basic_types_globals_metadata::U' +// gdbg-command:whatis 'basic_types_globals_metadata::U' +// gdbr-command:whatis basic_types_globals_metadata::U // gdb-check:type = usize -// gdb-command:whatis 'basic_types_globals_metadata::U8' +// gdbg-command:whatis 'basic_types_globals_metadata::U8' +// gdbr-command:whatis basic_types_globals_metadata::U8 // gdb-check:type = u8 -// gdb-command:whatis 'basic_types_globals_metadata::U16' +// gdbg-command:whatis 'basic_types_globals_metadata::U16' +// gdbr-command:whatis basic_types_globals_metadata::U16 // gdb-check:type = u16 -// gdb-command:whatis 'basic_types_globals_metadata::U32' +// gdbg-command:whatis 'basic_types_globals_metadata::U32' +// gdbr-command:whatis basic_types_globals_metadata::U32 // gdb-check:type = u32 -// gdb-command:whatis 'basic_types_globals_metadata::U64' +// gdbg-command:whatis 'basic_types_globals_metadata::U64' +// gdbr-command:whatis basic_types_globals_metadata::U64 // gdb-check:type = u64 -// gdb-command:whatis 'basic_types_globals_metadata::F32' +// gdbg-command:whatis 'basic_types_globals_metadata::F32' +// gdbr-command:whatis basic_types_globals_metadata::F32 // gdb-check:type = f32 -// gdb-command:whatis 'basic_types_globals_metadata::F64' +// gdbg-command:whatis 'basic_types_globals_metadata::F64' +// gdbr-command:whatis basic_types_globals_metadata::F64 // gdb-check:type = f64 // gdb-command:continue diff --git a/src/test/debuginfo/basic-types-globals.rs b/src/test/debuginfo/basic-types-globals.rs index ccf9508a38..20bc403fbb 100644 --- a/src/test/debuginfo/basic-types-globals.rs +++ b/src/test/debuginfo/basic-types-globals.rs @@ -18,33 +18,48 @@ // compile-flags:-g // gdb-command:run -// gdb-command:print 'basic_types_globals::B' +// gdbg-command:print 'basic_types_globals::B' +// gdbr-command:print B // gdb-check:$1 = false -// gdb-command:print 'basic_types_globals::I' +// gdbg-command:print 'basic_types_globals::I' +// gdbr-command:print I // gdb-check:$2 = -1 -// gdb-command:print 'basic_types_globals::C' -// gdb-check:$3 = 97 -// gdb-command:print/d 'basic_types_globals::I8' +// gdbg-command:print 'basic_types_globals::C' +// gdbr-command:print C +// gdbg-check:$3 = 97 +// gdbr-check:$3 = 97 'a' +// gdbg-command:print/d 'basic_types_globals::I8' +// gdbr-command:print I8 // gdb-check:$4 = 68 -// gdb-command:print 'basic_types_globals::I16' +// gdbg-command:print 'basic_types_globals::I16' +// gdbr-command:print I16 // gdb-check:$5 = -16 -// gdb-command:print 'basic_types_globals::I32' +// gdbg-command:print 'basic_types_globals::I32' +// gdbr-command:print I32 // gdb-check:$6 = -32 -// gdb-command:print 'basic_types_globals::I64' +// gdbg-command:print 'basic_types_globals::I64' +// gdbr-command:print I64 // gdb-check:$7 = -64 -// gdb-command:print 'basic_types_globals::U' +// gdbg-command:print 'basic_types_globals::U' +// gdbr-command:print U // gdb-check:$8 = 1 -// gdb-command:print/d 'basic_types_globals::U8' +// gdbg-command:print/d 'basic_types_globals::U8' +// gdbr-command:print U8 // gdb-check:$9 = 100 -// gdb-command:print 'basic_types_globals::U16' +// gdbg-command:print 'basic_types_globals::U16' +// gdbr-command:print U16 // gdb-check:$10 = 16 -// gdb-command:print 'basic_types_globals::U32' +// gdbg-command:print 'basic_types_globals::U32' +// gdbr-command:print U32 // gdb-check:$11 = 32 -// gdb-command:print 'basic_types_globals::U64' +// gdbg-command:print 'basic_types_globals::U64' +// gdbr-command:print U64 // gdb-check:$12 = 64 -// gdb-command:print 'basic_types_globals::F32' +// gdbg-command:print 'basic_types_globals::F32' +// gdbr-command:print F32 // gdb-check:$13 = 2.5 -// gdb-command:print 'basic_types_globals::F64' +// gdbg-command:print 'basic_types_globals::F64' +// gdbr-command:print F64 // gdb-check:$14 = 3.5 // gdb-command:continue diff --git a/src/test/debuginfo/basic-types-metadata.rs b/src/test/debuginfo/basic-types-metadata.rs index 1a6b605d9d..8aec1a059b 100644 --- a/src/test/debuginfo/basic-types-metadata.rs +++ b/src/test/debuginfo/basic-types-metadata.rs @@ -45,20 +45,29 @@ // gdb-command:whatis fnptr // gdb-check:type = [...] (*)([...]) // gdb-command:info functions _yyy -// gdb-check:[...]![...]_yyy([...]); +// gdbg-check:[...]![...]_yyy([...]); +// gdbr-check:static fn basic_types_metadata::_yyy() -> !; // gdb-command:ptype closure_0 -// gdb-check: type = struct closure { -// gdb-check: -// gdb-check: } +// gdbr-check: type = struct closure +// gdbg-check: type = struct closure { +// gdbg-check: +// gdbg-check: } // gdb-command:ptype closure_1 -// gdb-check: type = struct closure { -// gdb-check: bool *__0; -// gdb-check: } +// gdbg-check: type = struct closure { +// gdbg-check: bool *__0; +// gdbg-check: } +// gdbr-check: type = struct closure ( +// gdbr-check: bool *, +// gdbr-check: ) // gdb-command:ptype closure_2 -// gdb-check: type = struct closure { -// gdb-check: bool *__0; -// gdb-check: isize *__1; -// gdb-check: } +// gdbg-check: type = struct closure { +// gdbg-check: bool *__0; +// gdbg-check: isize *__1; +// gdbg-check: } +// gdbr-check: type = struct closure ( +// gdbr-check: bool *, +// gdbr-check: isize *, +// gdbr-check: ) // // gdb-command:continue diff --git a/src/test/debuginfo/basic-types-mut-globals.rs b/src/test/debuginfo/basic-types-mut-globals.rs index 4ebd0c9577..62325aa53a 100644 --- a/src/test/debuginfo/basic-types-mut-globals.rs +++ b/src/test/debuginfo/basic-types-mut-globals.rs @@ -21,64 +21,94 @@ // gdb-command:run // Check initializers -// gdb-command:print 'basic_types_mut_globals::B' +// gdbg-command:print 'basic_types_mut_globals::B' +// gdbr-command:print B // gdb-check:$1 = false -// gdb-command:print 'basic_types_mut_globals::I' +// gdbg-command:print 'basic_types_mut_globals::I' +// gdbr-command:print I // gdb-check:$2 = -1 -// gdb-command:print 'basic_types_mut_globals::C' -// gdb-check:$3 = 97 -// gdb-command:print/d 'basic_types_mut_globals::I8' +// gdbg-command:print/d 'basic_types_mut_globals::C' +// gdbr-command:print C +// gdbg-check:$3 = 97 +// gdbr-check:$3 = 97 'a' +// gdbg-command:print/d 'basic_types_mut_globals::I8' +// gdbr-command:print I8 // gdb-check:$4 = 68 -// gdb-command:print 'basic_types_mut_globals::I16' +// gdbg-command:print 'basic_types_mut_globals::I16' +// gdbr-command:print I16 // gdb-check:$5 = -16 -// gdb-command:print 'basic_types_mut_globals::I32' +// gdbg-command:print 'basic_types_mut_globals::I32' +// gdbr-command:print I32 // gdb-check:$6 = -32 -// gdb-command:print 'basic_types_mut_globals::I64' +// gdbg-command:print 'basic_types_mut_globals::I64' +// gdbr-command:print I64 // gdb-check:$7 = -64 -// gdb-command:print 'basic_types_mut_globals::U' +// gdbg-command:print 'basic_types_mut_globals::U' +// gdbr-command:print U // gdb-check:$8 = 1 -// gdb-command:print/d 'basic_types_mut_globals::U8' +// gdbg-command:print/d 'basic_types_mut_globals::U8' +// gdbr-command:print U8 // gdb-check:$9 = 100 -// gdb-command:print 'basic_types_mut_globals::U16' +// gdbg-command:print 'basic_types_mut_globals::U16' +// gdbr-command:print U16 // gdb-check:$10 = 16 -// gdb-command:print 'basic_types_mut_globals::U32' +// gdbg-command:print 'basic_types_mut_globals::U32' +// gdbr-command:print U32 // gdb-check:$11 = 32 -// gdb-command:print 'basic_types_mut_globals::U64' +// gdbg-command:print 'basic_types_mut_globals::U64' +// gdbr-command:print U64 // gdb-check:$12 = 64 -// gdb-command:print 'basic_types_mut_globals::F32' +// gdbg-command:print 'basic_types_mut_globals::F32' +// gdbr-command:print F32 // gdb-check:$13 = 2.5 -// gdb-command:print 'basic_types_mut_globals::F64' +// gdbg-command:print 'basic_types_mut_globals::F64' +// gdbr-command:print F64 // gdb-check:$14 = 3.5 // gdb-command:continue // Check new values -// gdb-command:print 'basic_types_mut_globals'::B +// gdbg-command:print 'basic_types_mut_globals'::B +// gdbr-command:print B // gdb-check:$15 = true -// gdb-command:print 'basic_types_mut_globals'::I +// gdbg-command:print 'basic_types_mut_globals'::I +// gdbr-command:print I // gdb-check:$16 = 2 -// gdb-command:print 'basic_types_mut_globals'::C -// gdb-check:$17 = 102 -// gdb-command:print/d 'basic_types_mut_globals'::I8 +// gdbg-command:print/d 'basic_types_mut_globals'::C +// gdbr-command:print C +// gdbg-check:$17 = 102 +// gdbr-check:$17 = 102 'f' +// gdbg-command:print/d 'basic_types_mut_globals'::I8 +// gdbr-command:print/d I8 // gdb-check:$18 = 78 -// gdb-command:print 'basic_types_mut_globals'::I16 +// gdbg-command:print 'basic_types_mut_globals'::I16 +// gdbr-command:print I16 // gdb-check:$19 = -26 -// gdb-command:print 'basic_types_mut_globals'::I32 +// gdbg-command:print 'basic_types_mut_globals'::I32 +// gdbr-command:print I32 // gdb-check:$20 = -12 -// gdb-command:print 'basic_types_mut_globals'::I64 +// gdbg-command:print 'basic_types_mut_globals'::I64 +// gdbr-command:print I64 // gdb-check:$21 = -54 -// gdb-command:print 'basic_types_mut_globals'::U +// gdbg-command:print 'basic_types_mut_globals'::U +// gdbr-command:print U // gdb-check:$22 = 5 -// gdb-command:print/d 'basic_types_mut_globals'::U8 +// gdbg-command:print/d 'basic_types_mut_globals'::U8 +// gdbr-command:print/d U8 // gdb-check:$23 = 20 -// gdb-command:print 'basic_types_mut_globals'::U16 +// gdbg-command:print 'basic_types_mut_globals'::U16 +// gdbr-command:print U16 // gdb-check:$24 = 32 -// gdb-command:print 'basic_types_mut_globals'::U32 +// gdbg-command:print 'basic_types_mut_globals'::U32 +// gdbr-command:print U32 // gdb-check:$25 = 16 -// gdb-command:print 'basic_types_mut_globals'::U64 +// gdbg-command:print 'basic_types_mut_globals'::U64 +// gdbr-command:print U64 // gdb-check:$26 = 128 -// gdb-command:print 'basic_types_mut_globals'::F32 +// gdbg-command:print 'basic_types_mut_globals'::F32 +// gdbr-command:print F32 // gdb-check:$27 = 5.75 -// gdb-command:print 'basic_types_mut_globals'::F64 +// gdbg-command:print 'basic_types_mut_globals'::F64 +// gdbr-command:print F64 // gdb-check:$28 = 9.25 #![allow(unused_variables)] diff --git a/src/test/debuginfo/basic-types.rs b/src/test/debuginfo/basic-types.rs index 9980108328..01ce5bd316 100644 --- a/src/test/debuginfo/basic-types.rs +++ b/src/test/debuginfo/basic-types.rs @@ -26,7 +26,8 @@ // gdb-command:print i // gdb-check:$2 = -1 // gdb-command:print c -// gdb-check:$3 = 97 +// gdbg-check:$3 = 97 +// gdbr-check:$3 = 97 'a' // gdb-command:print/d i8 // gdb-check:$4 = 68 // gdb-command:print i16 diff --git a/src/test/debuginfo/borrowed-basic.rs b/src/test/debuginfo/borrowed-basic.rs index bada77b662..f6c0ff09ef 100644 --- a/src/test/debuginfo/borrowed-basic.rs +++ b/src/test/debuginfo/borrowed-basic.rs @@ -25,10 +25,12 @@ // gdb-check:$2 = -1 // gdb-command:print *char_ref -// gdb-check:$3 = 97 +// gdbg-check:$3 = 97 +// gdbr-check:$3 = 97 'a' // gdb-command:print *i8_ref -// gdb-check:$4 = 68 'D' +// gdbg-check:$4 = 68 'D' +// gdbr-check:$4 = 68 // gdb-command:print *i16_ref // gdb-check:$5 = -16 @@ -43,7 +45,8 @@ // gdb-check:$8 = 1 // gdb-command:print *u8_ref -// gdb-check:$9 = 100 'd' +// gdbg-check:$9 = 100 'd' +// gdbr-check:$9 = 100 // gdb-command:print *u16_ref // gdb-check:$10 = 16 diff --git a/src/test/debuginfo/borrowed-c-style-enum.rs b/src/test/debuginfo/borrowed-c-style-enum.rs index c80783ef31..d6f379634b 100644 --- a/src/test/debuginfo/borrowed-c-style-enum.rs +++ b/src/test/debuginfo/borrowed-c-style-enum.rs @@ -17,13 +17,16 @@ // gdb-command:run // gdb-command:print *the_a_ref -// gdb-check:$1 = TheA +// gdbg-check:$1 = TheA +// gdbr-check:$1 = borrowed_c_style_enum::ABC::TheA // gdb-command:print *the_b_ref -// gdb-check:$2 = TheB +// gdbg-check:$2 = TheB +// gdbr-check:$2 = borrowed_c_style_enum::ABC::TheB // gdb-command:print *the_c_ref -// gdb-check:$3 = TheC +// gdbg-check:$3 = TheC +// gdbr-check:$3 = borrowed_c_style_enum::ABC::TheC // === LLDB TESTS ================================================================================== diff --git a/src/test/debuginfo/borrowed-enum.rs b/src/test/debuginfo/borrowed-enum.rs index b21574e328..ddc29c6430 100644 --- a/src/test/debuginfo/borrowed-enum.rs +++ b/src/test/debuginfo/borrowed-enum.rs @@ -18,13 +18,16 @@ // 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 = 0, __1 = 2088533116, __2 = 2088533116}} +// gdbg-check:$1 = {{RUST$ENUM$DISR = TheA, x = 0, y = 8970181431921507452}, {RUST$ENUM$DISR = TheA, __0 = 0, __1 = 2088533116, __2 = 2088533116}} +// gdbr-check:$1 = borrowed_enum::ABC::TheA{x: 0, y: 8970181431921507452} // gdb-command:print *the_b_ref -// gdb-check:$2 = {{RUST$ENUM$DISR = TheB, x = 0, y = 1229782938247303441}, {RUST$ENUM$DISR = TheB, __0 = 0, __1 = 286331153, __2 = 286331153}} +// gdbg-check:$2 = {{RUST$ENUM$DISR = TheB, x = 0, y = 1229782938247303441}, {RUST$ENUM$DISR = TheB, __0 = 0, __1 = 286331153, __2 = 286331153}} +// gdbr-check:$2 = borrowed_enum::ABC::TheB(0, 286331153, 286331153) // gdb-command:print *univariant_ref -// gdb-check:$3 = {{__0 = 4820353753753434}} +// gdbg-check:$3 = {{__0 = 4820353753753434}} +// gdbr-check:$3 = borrowed_enum::Univariant::TheOnlyCase(4820353753753434) // === LLDB TESTS ================================================================================== diff --git a/src/test/debuginfo/borrowed-struct.rs b/src/test/debuginfo/borrowed-struct.rs index ab41185cb7..01428e515e 100644 --- a/src/test/debuginfo/borrowed-struct.rs +++ b/src/test/debuginfo/borrowed-struct.rs @@ -16,7 +16,8 @@ // gdb-command:run // gdb-command:print *stack_val_ref -// gdb-check:$1 = {x = 10, y = 23.5} +// gdbg-check:$1 = {x = 10, y = 23.5} +// gdbr-check:$1 = borrowed_struct::SomeStruct {x: 10, y: 23.5} // gdb-command:print *stack_val_interior_ref_1 // gdb-check:$2 = 10 @@ -25,10 +26,12 @@ // gdb-check:$3 = 23.5 // gdb-command:print *ref_to_unnamed -// gdb-check:$4 = {x = 11, y = 24.5} +// gdbg-check:$4 = {x = 11, y = 24.5} +// gdbr-check:$4 = borrowed_struct::SomeStruct {x: 11, y: 24.5} // gdb-command:print *unique_val_ref -// gdb-check:$5 = {x = 13, y = 26.5} +// gdbg-check:$5 = {x = 13, y = 26.5} +// gdbr-check:$5 = borrowed_struct::SomeStruct {x: 13, y: 26.5} // gdb-command:print *unique_val_interior_ref_1 // gdb-check:$6 = 13 diff --git a/src/test/debuginfo/borrowed-tuple.rs b/src/test/debuginfo/borrowed-tuple.rs index e3da3934f6..17db88ee37 100644 --- a/src/test/debuginfo/borrowed-tuple.rs +++ b/src/test/debuginfo/borrowed-tuple.rs @@ -17,13 +17,16 @@ // gdb-command:run // gdb-command:print *stack_val_ref -// gdb-check:$1 = {__0 = -14, __1 = -19} +// gdbg-check:$1 = {__0 = -14, __1 = -19} +// gdbr-check:$1 = (-14, -19) // gdb-command:print *ref_to_unnamed -// gdb-check:$2 = {__0 = -15, __1 = -20} +// gdbg-check:$2 = {__0 = -15, __1 = -20} +// gdbr-check:$2 = (-15, -20) // gdb-command:print *unique_val_ref -// gdb-check:$3 = {__0 = -17, __1 = -22} +// gdbg-check:$3 = {__0 = -17, __1 = -22} +// gdbr-check:$3 = (-17, -22) // === LLDB TESTS ================================================================================== diff --git a/src/test/debuginfo/borrowed-unique-basic.rs b/src/test/debuginfo/borrowed-unique-basic.rs index 88af94c536..9e95498b0c 100644 --- a/src/test/debuginfo/borrowed-unique-basic.rs +++ b/src/test/debuginfo/borrowed-unique-basic.rs @@ -26,7 +26,8 @@ // gdb-check:$2 = -1 // gdb-command:print *char_ref -// gdb-check:$3 = 97 +// gdbg-check:$3 = 97 +// gdbr-check:$3 = 97 'a' // gdb-command:print/d *i8_ref // gdb-check:$4 = 68 diff --git a/src/test/debuginfo/box.rs b/src/test/debuginfo/box.rs index 106d0b243e..98c09fe09d 100644 --- a/src/test/debuginfo/box.rs +++ b/src/test/debuginfo/box.rs @@ -19,7 +19,8 @@ // gdb-command:print *a // gdb-check:$1 = 1 // gdb-command:print *b -// gdb-check:$2 = {__0 = 2, __1 = 3.5} +// gdbg-check:$2 = {__0 = 2, __1 = 3.5} +// gdbr-check:$2 = (2, 3.5) // === LLDB TESTS ================================================================================== diff --git a/src/test/debuginfo/boxed-struct.rs b/src/test/debuginfo/boxed-struct.rs index dd543405e4..ac091b4a53 100644 --- a/src/test/debuginfo/boxed-struct.rs +++ b/src/test/debuginfo/boxed-struct.rs @@ -17,10 +17,12 @@ // gdb-command:run // gdb-command:print *unique -// gdb-check:$1 = {x = 99, y = 999, z = 9999, w = 99999} +// gdbg-check:$1 = {x = 99, y = 999, z = 9999, w = 99999} +// gdbr-check:$1 = boxed_struct::StructWithSomePadding {x: 99, y: 999, z: 9999, w: 99999} // gdb-command:print *unique_dtor -// gdb-check:$2 = {x = 77, y = 777, z = 7777, w = 77777} +// gdbg-check:$2 = {x = 77, y = 777, z = 7777, w = 77777} +// gdbr-check:$2 = boxed_struct::StructWithDestructor {x: 77, y: 777, z: 7777, w: 77777} // === 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 a329ef6d0e..6d821dbc15 100644 --- a/src/test/debuginfo/by-value-non-immediate-argument.rs +++ b/src/test/debuginfo/by-value-non-immediate-argument.rs @@ -18,11 +18,13 @@ // gdb-command:run // gdb-command:print s -// gdb-check:$1 = {a = 1, b = 2.5} +// gdbg-check:$1 = {a = 1, b = 2.5} +// gdbr-check:$1 = by_value_non_immediate_argument::Struct {a: 1, b: 2.5} // gdb-command:continue // gdb-command:print x -// gdb-check:$2 = {a = 3, b = 4.5} +// gdbg-check:$2 = {a = 3, b = 4.5} +// gdbr-check:$2 = by_value_non_immediate_argument::Struct {a: 3, b: 4.5} // gdb-command:print y // gdb-check:$3 = 5 // gdb-command:print z @@ -30,15 +32,18 @@ // gdb-command:continue // gdb-command:print a -// gdb-check:$5 = {__0 = 7, __1 = 8, __2 = 9.5, __3 = 10.5} +// gdbg-check:$5 = {__0 = 7, __1 = 8, __2 = 9.5, __3 = 10.5} +// gdbr-check:$5 = (7, 8, 9.5, 10.5) // gdb-command:continue // gdb-command:print a -// gdb-check:$6 = {__0 = 11.5, __1 = 12.5, __2 = 13, __3 = 14} +// gdbg-check:$6 = {__0 = 11.5, __1 = 12.5, __2 = 13, __3 = 14} +// gdbr-check:$6 = by_value_non_immediate_argument::Newtype (11.5, 12.5, 13, 14) // gdb-command:continue // gdb-command:print x -// gdb-check:$7 = {{RUST$ENUM$DISR = Case1, x = 0, y = 8970181431921507452}, {RUST$ENUM$DISR = Case1, __0 = 0, __1 = 2088533116, __2 = 2088533116}} +// gdbg-check:$7 = {{RUST$ENUM$DISR = Case1, x = 0, y = 8970181431921507452}, {RUST$ENUM$DISR = Case1, __0 = 0, __1 = 2088533116, __2 = 2088533116}} +// gdbr-check:$7 = by_value_non_immediate_argument::Enum::Case1{x: 0, y: 8970181431921507452} // 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 a768bfdd16..c14f8c7b35 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 @@ -21,11 +21,13 @@ // gdb-command:continue // gdb-command:print self -// gdb-check:$2 = {x = 2222, y = 3333} +// gdbg-check:$2 = {x = 2222, y = 3333} +// gdbr-check:$2 = by_value_self_argument_in_trait_impl::Struct {x: 2222, y: 3333} // gdb-command:continue // gdb-command:print self -// gdb-check:$3 = {__0 = 4444.5, __1 = 5555, __2 = 6666, __3 = 7777.5} +// gdbg-check:$3 = {__0 = 4444.5, __1 = 5555, __2 = 6666, __3 = 7777.5} +// gdbr-check:$3 = (4444.5, 5555, 6666, 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 83a22edc96..004e15d1cc 100644 --- a/src/test/debuginfo/c-style-enum-in-composite.rs +++ b/src/test/debuginfo/c-style-enum-in-composite.rs @@ -18,26 +18,32 @@ // gdb-command:run // gdb-command:print tuple_interior_padding -// gdb-check:$1 = {__0 = 0, __1 = OneHundred} +// gdbg-check:$1 = {__0 = 0, __1 = OneHundred} +// gdbr-check:$1 = (0, c_style_enum_in_composite::AnEnum::OneHundred) // gdb-command:print tuple_padding_at_end -// gdb-check:$2 = {__0 = {__0 = 1, __1 = OneThousand}, __1 = 2} +// gdbg-check:$2 = {__0 = {__0 = 1, __1 = OneThousand}, __1 = 2} +// gdbr-check:$2 = ((1, c_style_enum_in_composite::AnEnum::OneThousand), 2) // gdb-command:print tuple_different_enums -// gdb-check:$3 = {__0 = OneThousand, __1 = MountainView, __2 = OneMillion, __3 = Vienna} +// gdbg-check:$3 = {__0 = OneThousand, __1 = MountainView, __2 = OneMillion, __3 = Vienna} +// gdbr-check:$3 = (c_style_enum_in_composite::AnEnum::OneThousand, c_style_enum_in_composite::AnotherEnum::MountainView, c_style_enum_in_composite::AnEnum::OneMillion, c_style_enum_in_composite::AnotherEnum::Vienna) // gdb-command:print padded_struct -// gdb-check:$4 = {a = 3, b = OneMillion, c = 4, d = Toronto, e = 5} +// gdbg-check:$4 = {a = 3, b = OneMillion, c = 4, d = Toronto, e = 5} +// gdbr-check:$4 = c_style_enum_in_composite::PaddedStruct {a: 3, b: c_style_enum_in_composite::AnEnum::OneMillion, c: 4, d: c_style_enum_in_composite::AnotherEnum::Toronto, e: 5} // gdb-command:print packed_struct -// gdb-check:$5 = {a = 6, b = OneHundred, c = 7, d = Vienna, e = 8} +// gdbg-check:$5 = {a = 6, b = OneHundred, c = 7, d = Vienna, e = 8} +// gdbr-check:$5 = c_style_enum_in_composite::PackedStruct {a: 6, b: c_style_enum_in_composite::AnEnum::OneHundred, c: 7, d: c_style_enum_in_composite::AnotherEnum::Vienna, e: 8} // gdb-command:print non_padded_struct -// gdb-check:$6 = {a = OneMillion, b = MountainView, c = OneThousand, d = Toronto} +// gdbg-check:$6 = {a = OneMillion, b = MountainView, c = OneThousand, d = Toronto} +// gdbr-check:$6 = c_style_enum_in_composite::NonPaddedStruct {a: c_style_enum_in_composite::AnEnum::OneMillion, b: c_style_enum_in_composite::AnotherEnum::MountainView, c: c_style_enum_in_composite::AnEnum::OneThousand, d: c_style_enum_in_composite::AnotherEnum::Toronto} // gdb-command:print struct_with_drop -// gdb-check:$7 = {__0 = {a = OneHundred, b = Vienna}, __1 = 9} - +// gdbg-check:$7 = {__0 = {a = OneHundred, b = Vienna}, __1 = 9} +// gdbr-check:$7 = (c_style_enum_in_composite::StructWithDrop {a: c_style_enum_in_composite::AnEnum::OneHundred, b: c_style_enum_in_composite::AnotherEnum::Vienna}, 9) // === LLDB TESTS ================================================================================== diff --git a/src/test/debuginfo/c-style-enum.rs b/src/test/debuginfo/c-style-enum.rs index dbd336d2dc..2452c18f54 100644 --- a/src/test/debuginfo/c-style-enum.rs +++ b/src/test/debuginfo/c-style-enum.rs @@ -16,60 +16,82 @@ // === GDB TESTS =================================================================================== // gdb-command:print 'c_style_enum::SINGLE_VARIANT' -// gdb-check:$1 = TheOnlyVariant +// gdbg-check:$1 = TheOnlyVariant +// gdbr-check:$1 = c_style_enum::SingleVariant::TheOnlyVariant // gdb-command:print 'c_style_enum::AUTO_ONE' -// gdb-check:$2 = One +// gdbg-check:$2 = One +// gdbr-check:$2 = c_style_enum::AutoDiscriminant::One // gdb-command:print 'c_style_enum::AUTO_TWO' -// gdb-check:$3 = One +// gdbg-check:$3 = One +// gdbr-check:$3 = c_style_enum::AutoDiscriminant::One // gdb-command:print 'c_style_enum::AUTO_THREE' -// gdb-check:$4 = One +// gdbg-check:$4 = One +// gdbr-check:$4 = c_style_enum::AutoDiscriminant::One // gdb-command:print 'c_style_enum::MANUAL_ONE' -// gdb-check:$5 = OneHundred +// gdbg-check:$5 = OneHundred +// gdbr-check:$5 = c_style_enum::ManualDiscriminant::OneHundred // gdb-command:print 'c_style_enum::MANUAL_TWO' -// gdb-check:$6 = OneHundred +// gdbg-check:$6 = OneHundred +// gdbr-check:$6 = c_style_enum::ManualDiscriminant::OneHundred // gdb-command:print 'c_style_enum::MANUAL_THREE' -// gdb-check:$7 = OneHundred +// gdbg-check:$7 = OneHundred +// gdbr-check:$7 = c_style_enum::ManualDiscriminant::OneHundred // gdb-command:run // gdb-command:print auto_one -// gdb-check:$8 = One +// gdbg-check:$8 = One +// gdbr-check:$8 = c_style_enum::AutoDiscriminant::One // gdb-command:print auto_two -// gdb-check:$9 = Two +// gdbg-check:$9 = Two +// gdbr-check:$9 = c_style_enum::AutoDiscriminant::Two // gdb-command:print auto_three -// gdb-check:$10 = Three +// gdbg-check:$10 = Three +// gdbr-check:$10 = c_style_enum::AutoDiscriminant::Three // gdb-command:print manual_one_hundred -// gdb-check:$11 = OneHundred +// gdbg-check:$11 = OneHundred +// gdbr-check:$11 = c_style_enum::ManualDiscriminant::OneHundred // gdb-command:print manual_one_thousand -// gdb-check:$12 = OneThousand +// gdbg-check:$12 = OneThousand +// gdbr-check:$12 = c_style_enum::ManualDiscriminant::OneThousand // gdb-command:print manual_one_million -// gdb-check:$13 = OneMillion +// gdbg-check:$13 = OneMillion +// gdbr-check:$13 = c_style_enum::ManualDiscriminant::OneMillion // gdb-command:print single_variant -// gdb-check:$14 = TheOnlyVariant - -// gdb-command:print 'c_style_enum::AUTO_TWO' -// gdb-check:$15 = Two - -// gdb-command:print 'c_style_enum::AUTO_THREE' -// gdb-check:$16 = Three - -// gdb-command:print 'c_style_enum::MANUAL_TWO' -// gdb-check:$17 = OneThousand - -// gdb-command:print 'c_style_enum::MANUAL_THREE' -// gdb-check:$18 = OneMillion +// gdbg-check:$14 = TheOnlyVariant +// gdbr-check:$14 = c_style_enum::SingleVariant::TheOnlyVariant + +// gdbg-command:print 'c_style_enum::AUTO_TWO' +// gdbr-command:print AUTO_TWO +// gdbg-check:$15 = Two +// gdbr-check:$15 = c_style_enum::AutoDiscriminant::Two + +// gdbg-command:print 'c_style_enum::AUTO_THREE' +// gdbr-command:print AUTO_THREE +// gdbg-check:$16 = Three +// gdbr-check:$16 = c_style_enum::AutoDiscriminant::Three + +// gdbg-command:print 'c_style_enum::MANUAL_TWO' +// gdbr-command:print MANUAL_TWO +// gdbg-check:$17 = OneThousand +// gdbr-check:$17 = c_style_enum::ManualDiscriminant::OneThousand + +// gdbg-command:print 'c_style_enum::MANUAL_THREE' +// gdbr-command:print MANUAL_THREE +// gdbg-check:$18 = OneMillion +// gdbr-check:$18 = c_style_enum::ManualDiscriminant::OneMillion // === LLDB TESTS ================================================================================== diff --git a/src/test/debuginfo/cross-crate-spans.rs b/src/test/debuginfo/cross-crate-spans.rs index 544fe2c66d..28728df928 100644 --- a/src/test/debuginfo/cross-crate-spans.rs +++ b/src/test/debuginfo/cross-crate-spans.rs @@ -25,7 +25,8 @@ extern crate cross_crate_spans; // gdb-command:run // gdb-command:print result -// gdb-check:$1 = {__0 = 17, __1 = 17} +// gdbg-check:$1 = {__0 = 17, __1 = 17} +// gdbr-check:$1 = (17, 17) // gdb-command:print a_variable // gdb-check:$2 = 123456789 // gdb-command:print another_variable @@ -33,7 +34,8 @@ extern crate cross_crate_spans; // gdb-command:continue // gdb-command:print result -// gdb-check:$4 = {__0 = 1212, __1 = 1212} +// gdbg-check:$4 = {__0 = 1212, __1 = 1212} +// gdbr-check:$4 = (1212, 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 954a7abe63..efa9ee59b2 100644 --- a/src/test/debuginfo/destructured-fn-argument.rs +++ b/src/test/debuginfo/destructured-fn-argument.rs @@ -33,13 +33,15 @@ // gdb-command:print a // gdb-check:$6 = 5 // gdb-command:print b -// gdb-check:$7 = {__0 = 6, __1 = 7} +// gdbg-check:$7 = {__0 = 6, __1 = 7} +// gdbr-check:$7 = (6, 7) // gdb-command:continue // gdb-command:print h // gdb-check:$8 = 8 // gdb-command:print i -// gdb-check:$9 = {a = 9, b = 10} +// gdbg-check:$9 = {a = 9, b = 10} +// gdbr-check:$9 = destructured_fn_argument::Struct {a: 9, b: 10} // gdb-command:print j // gdb-check:$10 = 11 // gdb-command:continue @@ -65,7 +67,8 @@ // gdb-command:print q // gdb-check:$17 = 20 // gdb-command:print r -// gdb-check:$18 = {a = 21, b = 22} +// gdbg-check:$18 = {a = 21, b = 22} +// gdbr-check:$18 = destructured_fn_argument::Struct {a: 21, b: 22} // gdb-command:continue // gdb-command:print s @@ -95,11 +98,13 @@ // gdb-command:continue // gdb-command:print aa -// gdb-check:$30 = {__0 = 34, __1 = 35} +// gdbg-check:$30 = {__0 = 34, __1 = 35} +// gdbr-check:$30 = (34, 35) // gdb-command:continue // gdb-command:print bb -// gdb-check:$31 = {__0 = 36, __1 = 37} +// gdbg-check:$31 = {__0 = 36, __1 = 37} +// gdbr-check:$31 = (36, 37) // gdb-command:continue // gdb-command:print cc @@ -107,17 +112,20 @@ // gdb-command:continue // gdb-command:print dd -// gdb-check:$33 = {__0 = 40, __1 = 41, __2 = 42} +// gdbg-check:$33 = {__0 = 40, __1 = 41, __2 = 42} +// gdbr-check:$33 = (40, 41, 42) // gdb-command:continue // gdb-command:print *ee -// gdb-check:$34 = {__0 = 43, __1 = 44, __2 = 45} +// gdbg-check:$34 = {__0 = 43, __1 = 44, __2 = 45} +// gdbr-check:$34 = (43, 44, 45) // gdb-command:continue // gdb-command:print *ff // gdb-check:$35 = 46 // gdb-command:print gg -// gdb-check:$36 = {__0 = 47, __1 = 48} +// gdbg-check:$36 = {__0 = 47, __1 = 48} +// gdbr-check:$36 = (47, 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 a34d5d6adb..e973c22fd4 100644 --- a/src/test/debuginfo/destructured-for-loop-variable.rs +++ b/src/test/debuginfo/destructured-for-loop-variable.rs @@ -73,11 +73,13 @@ // gdb-command:continue // gdb-command:print simple_struct_ident -// gdb-check:$23 = {x = 3537, y = 35437.5, z = true} +// gdbg-check:$23 = {x = 3537, y = 35437.5, z = true} +// gdbr-check:$23 = destructured_for_loop_variable::Struct {x: 3537, y: 35437.5, z: true} // gdb-command:continue // gdb-command:print simple_tuple_ident -// gdb-check:$24 = {__0 = 34903493, __1 = 232323} +// gdbg-check:$24 = {__0 = 34903493, __1 = 232323} +// gdbr-check:$24 = (34903493, 232323) // gdb-command:continue // === LLDB TESTS ================================================================================== diff --git a/src/test/debuginfo/destructured-local.rs b/src/test/debuginfo/destructured-local.rs index a43e4546d4..1f18b77ab8 100644 --- a/src/test/debuginfo/destructured-local.rs +++ b/src/test/debuginfo/destructured-local.rs @@ -31,12 +31,14 @@ // gdb-command:print f // gdb-check:$6 = 5 // gdb-command:print g -// gdb-check:$7 = {__0 = 6, __1 = 7} +// gdbg-check:$7 = {__0 = 6, __1 = 7} +// gdbr-check:$7 = (6, 7) // gdb-command:print h // gdb-check:$8 = 8 // gdb-command:print i -// gdb-check:$9 = {a = 9, b = 10} +// gdbg-check:$9 = {a = 9, b = 10} +// gdbr-check:$9 = destructured_local::Struct {a: 9, b: 10} // gdb-command:print j // gdb-check:$10 = 11 @@ -58,7 +60,8 @@ // gdb-command:print q // gdb-check:$17 = 20 // gdb-command:print r -// gdb-check:$18 = {a = 21, b = 22} +// gdbg-check:$18 = {a = 21, b = 22} +// gdbr-check:$18 = destructured_local::Struct {a: 21, b: 22} // gdb-command:print s // gdb-check:$19 = 24 @@ -85,25 +88,30 @@ // gdb-check:$29 = 33 // gdb-command:print aa -// gdb-check:$30 = {__0 = 34, __1 = 35} +// gdbg-check:$30 = {__0 = 34, __1 = 35} +// gdbr-check:$30 = (34, 35) // gdb-command:print bb -// gdb-check:$31 = {__0 = 36, __1 = 37} +// gdbg-check:$31 = {__0 = 36, __1 = 37} +// gdbr-check:$31 = (36, 37) // gdb-command:print cc // gdb-check:$32 = 38 // gdb-command:print dd -// gdb-check:$33 = {__0 = 40, __1 = 41, __2 = 42} +// gdbg-check:$33 = {__0 = 40, __1 = 41, __2 = 42} +// gdbr-check:$33 = (40, 41, 42) // gdb-command:print *ee -// gdb-check:$34 = {__0 = 43, __1 = 44, __2 = 45} +// gdbg-check:$34 = {__0 = 43, __1 = 44, __2 = 45} +// gdbr-check:$34 = (43, 44, 45) // gdb-command:print *ff // gdb-check:$35 = 46 // gdb-command:print gg -// gdb-check:$36 = {__0 = 47, __1 = 48} +// gdbg-check:$36 = {__0 = 47, __1 = 48} +// gdbr-check:$36 = (47, 48) // gdb-command:print *hh // gdb-check:$37 = 50 diff --git a/src/test/debuginfo/drop-locations.rs b/src/test/debuginfo/drop-locations.rs new file mode 100644 index 0000000000..3a7c534c13 --- /dev/null +++ b/src/test/debuginfo/drop-locations.rs @@ -0,0 +1,91 @@ +// Copyright 2013-2016 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 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 +// min-lldb-version: 310 + +#![allow(unused)] + +// compile-flags:-g + +// This test checks that drop glue code gets attributed to scope's closing brace, +// and function epilogues - to function's closing brace. + +// === GDB TESTS =================================================================================== + +// gdb-command:run +// gdb-command:next +// gdb-command:frame +// gdb-check:[...]#loc1[...] +// gdb-command:next +// gdb-command:frame +// gdb-check:[...]#loc2[...] +// gdb-command:next +// gdb-command:frame +// gdb-check:[...]#loc3[...] +// gdb-command:next +// gdb-command:frame +// gdb-check:[...]#loc4[...] +// gdb-command:next +// gdb-command:frame +// gdb-check:[...]#loc5[...] +// gdb-command:next +// gdb-command:frame +// gdb-check:[...]#loc6[...] + +// === LLDB TESTS ================================================================================== + +// lldb-command:set set stop-line-count-before 0 +// lldb-command:set set stop-line-count-after 1 +// Can't set both to zero or lldb will stop printing source at all. So it will output the current +// line and the next. We deal with this by having at least 2 lines between the #loc's + +// lldb-command:run +// lldb-command:next +// lldb-command:frame select +// lldb-check:[...]#loc1[...] +// lldb-command:next +// lldb-command:frame select +// lldb-check:[...]#loc2[...] +// lldb-command:next +// lldb-command:frame select +// lldb-check:[...]#loc3[...] +// lldb-command:next +// lldb-command:frame select +// lldb-check:[...]#loc4[...] +// lldb-command:next +// lldb-command:frame select +// lldb-check:[...]#loc5[...] +// lldb-command:next +// lldb-command:frame select +// lldb-check:[...]#loc6[...] + +fn main() { + + foo(); + + zzz(); // #loc5 + +} // #loc6 + +fn foo() { + { + let s = String::from("s"); // #break + + zzz(); // #loc1 + + } // #loc2 + + zzz(); // #loc3 + +} // #loc4 + +fn zzz() {()} diff --git a/src/test/debuginfo/evec-in-struct.rs b/src/test/debuginfo/evec-in-struct.rs index 8624a0cba0..2e15157759 100644 --- a/src/test/debuginfo/evec-in-struct.rs +++ b/src/test/debuginfo/evec-in-struct.rs @@ -17,18 +17,23 @@ // gdb-command:run // gdb-command:print no_padding1 -// gdb-check:$1 = {x = {0, 1, 2}, y = -3, z = {4.5, 5.5}} +// gdbg-check:$1 = {x = {0, 1, 2}, y = -3, z = {4.5, 5.5}} +// gdbr-check:$1 = evec_in_struct::NoPadding1 {x: [0, 1, 2], y: -3, z: [4.5, 5.5]} // gdb-command:print no_padding2 -// gdb-check:$2 = {x = {6, 7, 8}, y = {{9, 10}, {11, 12}}} +// gdbg-check:$2 = {x = {6, 7, 8}, y = {{9, 10}, {11, 12}}} +// gdbr-check:$2 = evec_in_struct::NoPadding2 {x: [6, 7, 8], y: [[9, 10], [11, 12]]} // gdb-command:print struct_internal_padding -// gdb-check:$3 = {x = {13, 14}, y = {15, 16}} +// gdbg-check:$3 = {x = {13, 14}, y = {15, 16}} +// gdbr-check:$3 = evec_in_struct::StructInternalPadding {x: [13, 14], y: [15, 16]} // gdb-command:print single_vec -// gdb-check:$4 = {x = {17, 18, 19, 20, 21}} +// gdbg-check:$4 = {x = {17, 18, 19, 20, 21}} +// gdbr-check:$4 = evec_in_struct::SingleVec {x: [17, 18, 19, 20, 21]} // gdb-command:print struct_padded_at_end -// gdb-check:$5 = {x = {22, 23}, y = {24, 25}} +// gdbg-check:$5 = {x = {22, 23}, y = {24, 25}} +// gdbr-check:$5 = evec_in_struct::StructPaddedAtEnd {x: [22, 23], y: [24, 25]} // === LLDB TESTS ================================================================================== diff --git a/src/test/debuginfo/extern-c-fn.rs b/src/test/debuginfo/extern-c-fn.rs index c93db41dc5..01901b2c42 100644 --- a/src/test/debuginfo/extern-c-fn.rs +++ b/src/test/debuginfo/extern-c-fn.rs @@ -16,7 +16,8 @@ // gdb-command:run // gdb-command:print s -// gdb-check:$1 = [...]"abcd" +// gdbg-check:$1 = [...]"abcd" +// gdbr-check:$1 = [...]"abcd\000" // gdb-command:print len // gdb-check:$2 = 20 // gdb-command:print local0 diff --git a/src/test/debuginfo/function-arg-initialization.rs b/src/test/debuginfo/function-arg-initialization.rs index 57654acaf7..21fdc4e5e8 100644 --- a/src/test/debuginfo/function-arg-initialization.rs +++ b/src/test/debuginfo/function-arg-initialization.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 // This test case checks if function arguments already have the correct value @@ -34,9 +36,11 @@ // NON IMMEDIATE ARGS // gdb-command:print a -// gdb-check:$4 = {a = 3, b = 4, c = 5, d = 6, e = 7, f = 8, g = 9, h = 10} +// gdbg-check:$4 = {a = 3, b = 4, c = 5, d = 6, e = 7, f = 8, g = 9, h = 10} +// gdbt-check:$4 = function_arg_initialization::BigStruct {a: 3, b: 4, c: 5, d: 6, e: 7, f: 8, g: 9, h: 10} // gdb-command:print b -// gdb-check:$5 = {a = 11, b = 12, c = 13, d = 14, e = 15, f = 16, g = 17, h = 18} +// gdbg-check:$5 = {a = 11, b = 12, c = 13, d = 14, e = 15, f = 16, g = 17, h = 18} +// gdbt-check:$5 = function_arg_initialization::BigStruct {a: 11, b: 12, c: 13, d: 14, e: 15, f: 16, g: 17, h: 18} // gdb-command:continue // BINDING 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 81743a367e..158a1f17fc 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 @@ -26,13 +26,16 @@ // gdb-check:$2 = EmptyStruct // gdb-command: print c_style_enum1 -// gdb-check:$3 = CStyleEnumVar1 +// gdbg-check:$3 = CStyleEnumVar1 +// gdbr-check:$3 = gdb_pretty_struct_and_enums_pre_gdb_7_7::CStyleEnum::CStyleEnumVar1 // gdb-command: print c_style_enum2 -// gdb-check:$4 = CStyleEnumVar2 +// gdbg-check:$4 = CStyleEnumVar2 +// gdbr-check:$4 = gdb_pretty_struct_and_enums_pre_gdb_7_7::CStyleEnum::CStyleEnumVar2 // gdb-command: print c_style_enum3 -// gdb-check:$5 = CStyleEnumVar3 +// gdbg-check:$5 = CStyleEnumVar3 +// gdbr-check:$5 = gdb_pretty_struct_and_enums_pre_gdb_7_7::CStyleEnum::CStyleEnumVar3 #![allow(dead_code, unused_variables)] diff --git a/src/test/debuginfo/generic-enum-with-different-disr-sizes.rs b/src/test/debuginfo/generic-enum-with-different-disr-sizes.rs index 3115b3f7e7..1fc05b3752 100644 --- a/src/test/debuginfo/generic-enum-with-different-disr-sizes.rs +++ b/src/test/debuginfo/generic-enum-with-different-disr-sizes.rs @@ -18,22 +18,37 @@ // gdb-command:run // gdb-command:print eight_bytes1 -// gdb-check:$1 = {{RUST$ENUM$DISR = Variant1, __0 = 100}, {RUST$ENUM$DISR = Variant1, __0 = 100}} +// gdbg-check:$1 = {{RUST$ENUM$DISR = Variant1, __0 = 100}, {RUST$ENUM$DISR = Variant1, __0 = 100}} +// gdbr-check:$1 = generic_enum_with_different_disr_sizes::Enum::Variant1(100) + // gdb-command:print four_bytes1 -// gdb-check:$2 = {{RUST$ENUM$DISR = Variant1, __0 = 101}, {RUST$ENUM$DISR = Variant1, __0 = 101}} +// gdbg-check:$2 = {{RUST$ENUM$DISR = Variant1, __0 = 101}, {RUST$ENUM$DISR = Variant1, __0 = 101}} +// gdbr-check:$2 = generic_enum_with_different_disr_sizes::Enum::Variant1(101) + // gdb-command:print two_bytes1 -// gdb-check:$3 = {{RUST$ENUM$DISR = Variant1, __0 = 102}, {RUST$ENUM$DISR = Variant1, __0 = 102}} +// gdbg-check:$3 = {{RUST$ENUM$DISR = Variant1, __0 = 102}, {RUST$ENUM$DISR = Variant1, __0 = 102}} +// gdbr-check:$3 = generic_enum_with_different_disr_sizes::Enum::Variant1(102) + // gdb-command:print one_byte1 -// gdb-check:$4 = {{RUST$ENUM$DISR = Variant1, __0 = 65 'A'}, {RUST$ENUM$DISR = Variant1, __0 = 65 'A'}} +// gdbg-check:$4 = {{RUST$ENUM$DISR = Variant1, __0 = 65 'A'}, {RUST$ENUM$DISR = Variant1, __0 = 65 'A'}} +// gdbr-check:$4 = generic_enum_with_different_disr_sizes::Enum::Variant1(65) + // gdb-command:print eight_bytes2 -// gdb-check:$5 = {{RUST$ENUM$DISR = Variant2, __0 = 100}, {RUST$ENUM$DISR = Variant2, __0 = 100}} +// gdbg-check:$5 = {{RUST$ENUM$DISR = Variant2, __0 = 100}, {RUST$ENUM$DISR = Variant2, __0 = 100}} +// gdbr-check:$5 = generic_enum_with_different_disr_sizes::Enum::Variant2(100) + // gdb-command:print four_bytes2 -// gdb-check:$6 = {{RUST$ENUM$DISR = Variant2, __0 = 101}, {RUST$ENUM$DISR = Variant2, __0 = 101}} +// gdbg-check:$6 = {{RUST$ENUM$DISR = Variant2, __0 = 101}, {RUST$ENUM$DISR = Variant2, __0 = 101}} +// gdbr-check:$6 = generic_enum_with_different_disr_sizes::Enum::Variant2(101) + // gdb-command:print two_bytes2 -// gdb-check:$7 = {{RUST$ENUM$DISR = Variant2, __0 = 102}, {RUST$ENUM$DISR = Variant2, __0 = 102}} +// gdbg-check:$7 = {{RUST$ENUM$DISR = Variant2, __0 = 102}, {RUST$ENUM$DISR = Variant2, __0 = 102}} +// gdbr-check:$7 = generic_enum_with_different_disr_sizes::Enum::Variant2(102) + // gdb-command:print one_byte2 -// gdb-check:$8 = {{RUST$ENUM$DISR = Variant2, __0 = 65 'A'}, {RUST$ENUM$DISR = Variant2, __0 = 65 'A'}} +// gdbg-check:$8 = {{RUST$ENUM$DISR = Variant2, __0 = 65 'A'}, {RUST$ENUM$DISR = Variant2, __0 = 65 'A'}} +// gdbr-check:$8 = generic_enum_with_different_disr_sizes::Enum::Variant2(65) // gdb-command:continue diff --git a/src/test/debuginfo/generic-function.rs b/src/test/debuginfo/generic-function.rs index 415dd36212..f1bfc08915 100644 --- a/src/test/debuginfo/generic-function.rs +++ b/src/test/debuginfo/generic-function.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 @@ -21,7 +23,8 @@ // gdb-command:print *t1 // gdb-check:$2 = 2.5 // gdb-command:print ret -// gdb-check:$3 = {__0 = {__0 = 1, __1 = 2.5}, __1 = {__0 = 2.5, __1 = 1}} +// gdbg-check:$3 = {__0 = {__0 = 1, __1 = 2.5}, __1 = {__0 = 2.5, __1 = 1}} +// gdbr-check:$3 = ((1, 2.5), (2.5, 1)) // gdb-command:continue // gdb-command:print *t0 @@ -29,15 +32,18 @@ // gdb-command:print *t1 // gdb-check:$5 = 4 // gdb-command:print ret -// gdb-check:$6 = {__0 = {__0 = 3.5, __1 = 4}, __1 = {__0 = 4, __1 = 3.5}} +// gdbg-check:$6 = {__0 = {__0 = 3.5, __1 = 4}, __1 = {__0 = 4, __1 = 3.5}} +// gdbr-check:$6 = ((3.5, 4), (4, 3.5)) // gdb-command:continue // gdb-command:print *t0 // gdb-check:$7 = 5 // gdb-command:print *t1 -// gdb-check:$8 = {a = 6, b = 7.5} +// gdbg-check:$8 = {a = 6, b = 7.5} +// gdbr-check:$8 = generic_function::Struct {a: 6, b: 7.5} // gdb-command:print ret -// gdb-check:$9 = {__0 = {__0 = 5, __1 = {a = 6, b = 7.5}}, __1 = {__0 = {a = 6, b = 7.5}, __1 = 5}} +// gdbg-check:$9 = {__0 = {__0 = 5, __1 = {a = 6, b = 7.5}}, __1 = {__0 = {a = 6, b = 7.5}, __1 = 5}} +// gdbr-check:$9 = ((5, generic_function::Struct {a: 6, b: 7.5}), (generic_function::Struct {a: 6, b: 7.5}, 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 968cb2e159..4f3f6dfc82 100644 --- a/src/test/debuginfo/generic-method-on-generic-struct.rs +++ b/src/test/debuginfo/generic-method-on-generic-struct.rs @@ -18,7 +18,8 @@ // STACK BY REF // gdb-command:print *self -// gdb-check:$1 = {x = {__0 = 8888, __1 = -8888}} +// gdbg-check:$1 = {x = {__0 = 8888, __1 = -8888}} +// gdbr-check:$1 = generic_method_on_generic_struct::Struct<(u32, i32)> {x: (8888, -8888)} // gdb-command:print arg1 // gdb-check:$2 = -1 // gdb-command:print arg2 @@ -27,7 +28,8 @@ // STACK BY VAL // gdb-command:print self -// gdb-check:$4 = {x = {__0 = 8888, __1 = -8888}} +// gdbg-check:$4 = {x = {__0 = 8888, __1 = -8888}} +// gdbr-check:$4 = generic_method_on_generic_struct::Struct<(u32, i32)> {x: (8888, -8888)} // gdb-command:print arg1 // gdb-check:$5 = -3 // gdb-command:print arg2 @@ -36,7 +38,8 @@ // OWNED BY REF // gdb-command:print *self -// gdb-check:$7 = {x = 1234.5} +// gdbg-check:$7 = {x = 1234.5} +// gdbr-check:$7 = generic_method_on_generic_struct::Struct {x: 1234.5} // gdb-command:print arg1 // gdb-check:$8 = -5 // gdb-command:print arg2 @@ -45,7 +48,8 @@ // OWNED BY VAL // gdb-command:print self -// gdb-check:$10 = {x = 1234.5} +// gdbg-check:$10 = {x = 1234.5} +// gdbr-check:$10 = generic_method_on_generic_struct::Struct {x: 1234.5} // gdb-command:print arg1 // gdb-check:$11 = -7 // gdb-command:print arg2 @@ -54,7 +58,8 @@ // OWNED MOVED // gdb-command:print *self -// gdb-check:$13 = {x = 1234.5} +// gdbg-check:$13 = {x = 1234.5} +// gdbr-check:$13 = generic_method_on_generic_struct::Struct {x: 1234.5} // gdb-command:print arg1 // gdb-check:$14 = -9 // gdb-command:print arg2 diff --git a/src/test/debuginfo/generic-struct-style-enum.rs b/src/test/debuginfo/generic-struct-style-enum.rs index 991404f56e..dba9422721 100644 --- a/src/test/debuginfo/generic-struct-style-enum.rs +++ b/src/test/debuginfo/generic-struct-style-enum.rs @@ -17,16 +17,20 @@ // gdb-command:run // gdb-command:print case1 -// gdb-check:$1 = {{RUST$ENUM$DISR = Case1, a = 0, b = 31868, c = 31868, d = 31868, e = 31868}, {RUST$ENUM$DISR = Case1, a = 0, b = 2088533116, c = 2088533116}, {RUST$ENUM$DISR = Case1, a = 0, b = 8970181431921507452}} +// gdbg-check:$1 = {{RUST$ENUM$DISR = Case1, a = 0, b = 31868, c = 31868, d = 31868, e = 31868}, {RUST$ENUM$DISR = Case1, a = 0, b = 2088533116, c = 2088533116}, {RUST$ENUM$DISR = Case1, a = 0, b = 8970181431921507452}} +// gdbr-check:$1 = generic_struct_style_enum::Regular::Case1{a: 0, b: 31868, c: 31868, d: 31868, e: 31868} // gdb-command:print case2 -// gdb-check:$2 = {{RUST$ENUM$DISR = Case2, a = 0, b = 4369, c = 4369, d = 4369, e = 4369}, {RUST$ENUM$DISR = Case2, a = 0, b = 286331153, c = 286331153}, {RUST$ENUM$DISR = Case2, a = 0, b = 1229782938247303441}} +// gdbg-check:$2 = {{RUST$ENUM$DISR = Case2, a = 0, b = 4369, c = 4369, d = 4369, e = 4369}, {RUST$ENUM$DISR = Case2, a = 0, b = 286331153, c = 286331153}, {RUST$ENUM$DISR = Case2, a = 0, b = 1229782938247303441}} +// gdbr-check:$2 = generic_struct_style_enum::Regular::Case2{a: 0, b: 286331153, c: 286331153} // gdb-command:print case3 -// gdb-check:$3 = {{RUST$ENUM$DISR = Case3, a = 0, b = 22873, c = 22873, d = 22873, e = 22873}, {RUST$ENUM$DISR = Case3, a = 0, b = 1499027801, c = 1499027801}, {RUST$ENUM$DISR = Case3, a = 0, b = 6438275382588823897}} +// gdbg-check:$3 = {{RUST$ENUM$DISR = Case3, a = 0, b = 22873, c = 22873, d = 22873, e = 22873}, {RUST$ENUM$DISR = Case3, a = 0, b = 1499027801, c = 1499027801}, {RUST$ENUM$DISR = Case3, a = 0, b = 6438275382588823897}} +// gdbr-check:$3 = generic_struct_style_enum::Regular::Case3{a: 0, b: 6438275382588823897} // gdb-command:print univariant -// gdb-check:$4 = {{a = -1}} +// gdbg-check:$4 = {{a = -1}} +// gdbr-check:$4 = generic_struct_style_enum::Univariant::TheOnlyCase{a: -1} #![feature(omit_gdb_pretty_printer_section)] diff --git a/src/test/debuginfo/generic-struct.rs b/src/test/debuginfo/generic-struct.rs index 92a67a2344..35f00ce787 100644 --- a/src/test/debuginfo/generic-struct.rs +++ b/src/test/debuginfo/generic-struct.rs @@ -18,13 +18,17 @@ // gdb-command:run // gdb-command:print int_int -// gdb-check:$1 = {key = 0, value = 1} +// gdbg-check:$1 = {key = 0, value = 1} +// gdbr-check:$1 = generic_struct::AGenericStruct {key: 0, value: 1} // gdb-command:print int_float -// gdb-check:$2 = {key = 2, value = 3.5} +// gdbg-check:$2 = {key = 2, value = 3.5} +// gdbr-check:$2 = generic_struct::AGenericStruct {key: 2, value: 3.5} // gdb-command:print float_int -// gdb-check:$3 = {key = 4.5, value = 5} +// gdbg-check:$3 = {key = 4.5, value = 5} +// gdbr-check:$3 = generic_struct::AGenericStruct {key: 4.5, value: 5} // gdb-command:print float_int_float -// gdb-check:$4 = {key = 6.5, value = {key = 7, value = 8.5}} +// gdbg-check:$4 = {key = 6.5, value = {key = 7, value = 8.5}} +// gdbr-check:$4 = generic_struct::AGenericStruct> {key: 6.5, value: generic_struct::AGenericStruct {key: 7, value: 8.5}} // === LLDB TESTS ================================================================================== diff --git a/src/test/debuginfo/generic-tuple-style-enum.rs b/src/test/debuginfo/generic-tuple-style-enum.rs index e2727fbe7d..01d2ff4e33 100644 --- a/src/test/debuginfo/generic-tuple-style-enum.rs +++ b/src/test/debuginfo/generic-tuple-style-enum.rs @@ -19,16 +19,20 @@ // gdb-command:run // gdb-command:print case1 -// 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}} +// gdbg-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}} +// gdbr-check:$1 = generic_tuple_style_enum::Regular::Case1(0, 31868, 31868, 31868, 31868) // gdb-command:print case2 -// 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}} +// gdbg-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}} +// gdbr-check:$2 = generic_tuple_style_enum::Regular::Case2(0, 286331153, 286331153) // gdb-command:print case3 -// 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}} +// gdbg-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}} +// gdbr-check:$3 = generic_tuple_style_enum::Regular::Case3(0, 6438275382588823897) // gdb-command:print univariant -// gdb-check:$4 = {{__0 = -1}} +// gdbg-check:$4 = {{__0 = -1}} +// gdbr-check:$4 = generic_tuple_style_enum::Univariant::TheOnlyCase(-1) // === LLDB TESTS ================================================================================== diff --git a/src/test/debuginfo/issue14411.rs b/src/test/debuginfo/issue14411.rs index 3b2d372117..d334e33f88 100644 --- a/src/test/debuginfo/issue14411.rs +++ b/src/test/debuginfo/issue14411.rs @@ -20,6 +20,6 @@ fn test(a: &Vec) { } pub fn main() { - let data = vec!(); + let data = vec![]; test(&data); } diff --git a/src/test/debuginfo/lexical-scopes-in-block-expression.rs b/src/test/debuginfo/lexical-scopes-in-block-expression.rs index 841786f930..8e8a194e37 100644 --- a/src/test/debuginfo/lexical-scopes-in-block-expression.rs +++ b/src/test/debuginfo/lexical-scopes-in-block-expression.rs @@ -16,7 +16,8 @@ // gdb-command:run -// gdb-command:print 'lexical_scopes_in_block_expression::MUT_INT' +// gdbg-command:print 'lexical_scopes_in_block_expression::MUT_INT' +// gdbr-command:print lexical_scopes_in_block_expression::MUT_INT // gdb-check:$1 = 0 // STRUCT EXPRESSION @@ -28,7 +29,8 @@ // gdb-command:print val // gdb-check:$4 = 11 -// gdb-command:print 'lexical_scopes_in_block_expression::MUT_INT' +// gdbg-command:print 'lexical_scopes_in_block_expression::MUT_INT' +// gdbr-command:print lexical_scopes_in_block_expression::MUT_INT // gdb-check:$5 = 1 // gdb-command:print ten // gdb-check:$6 = 10 @@ -49,7 +51,8 @@ // gdb-command:print val // gdb-check:$11 = 12 -// gdb-command:print 'lexical_scopes_in_block_expression::MUT_INT' +// gdbg-command:print 'lexical_scopes_in_block_expression::MUT_INT' +// gdbr-command:print lexical_scopes_in_block_expression::MUT_INT // gdb-check:$12 = 2 // gdb-command:print ten // gdb-check:$13 = 10 @@ -70,7 +73,8 @@ // gdb-command:print val // gdb-check:$18 = 13 -// gdb-command:print 'lexical_scopes_in_block_expression::MUT_INT' +// gdbg-command:print 'lexical_scopes_in_block_expression::MUT_INT' +// gdbr-command:print lexical_scopes_in_block_expression::MUT_INT // gdb-check:$19 = 3 // gdb-command:print ten // gdb-check:$20 = 10 @@ -91,7 +95,8 @@ // gdb-command:print val // gdb-check:$25 = 14 -// gdb-command:print 'lexical_scopes_in_block_expression::MUT_INT' +// gdbg-command:print 'lexical_scopes_in_block_expression::MUT_INT' +// gdbr-command:print lexical_scopes_in_block_expression::MUT_INT // gdb-check:$26 = 4 // gdb-command:print ten // gdb-check:$27 = 10 @@ -112,7 +117,8 @@ // gdb-command:print val // gdb-check:$32 = 15 -// gdb-command:print 'lexical_scopes_in_block_expression::MUT_INT' +// gdbg-command:print 'lexical_scopes_in_block_expression::MUT_INT' +// gdbr-command:print lexical_scopes_in_block_expression::MUT_INT // gdb-check:$33 = 5 // gdb-command:print ten // gdb-check:$34 = 10 @@ -133,7 +139,8 @@ // gdb-command:print val // gdb-check:$39 = 16 -// gdb-command:print 'lexical_scopes_in_block_expression::MUT_INT' +// gdbg-command:print 'lexical_scopes_in_block_expression::MUT_INT' +// gdbr-command:print lexical_scopes_in_block_expression::MUT_INT // gdb-check:$40 = 6 // gdb-command:print ten // gdb-check:$41 = 10 @@ -155,7 +162,8 @@ // gdb-command:print val // gdb-check:$46 = 17 -// gdb-command:print 'lexical_scopes_in_block_expression::MUT_INT' +// gdbg-command:print 'lexical_scopes_in_block_expression::MUT_INT' +// gdbr-command:print lexical_scopes_in_block_expression::MUT_INT // gdb-check:$47 = 7 // gdb-command:print ten // gdb-check:$48 = 10 @@ -176,7 +184,8 @@ // gdb-command:print val // gdb-check:$53 = 18 -// gdb-command:print 'lexical_scopes_in_block_expression::MUT_INT' +// gdbg-command:print 'lexical_scopes_in_block_expression::MUT_INT' +// gdbr-command:print lexical_scopes_in_block_expression::MUT_INT // gdb-check:$54 = 8 // gdb-command:print ten // gdb-check:$55 = 10 diff --git a/src/test/debuginfo/method-on-enum.rs b/src/test/debuginfo/method-on-enum.rs index 6437b3bb90..7dbc0d3c51 100644 --- a/src/test/debuginfo/method-on-enum.rs +++ b/src/test/debuginfo/method-on-enum.rs @@ -19,7 +19,8 @@ // STACK BY REF // gdb-command:print *self -// gdb-check:$1 = {{RUST$ENUM$DISR = Variant2, [...]}, {RUST$ENUM$DISR = Variant2, __0 = 117901063}} +// gdbg-check:$1 = {{RUST$ENUM$DISR = Variant2, [...]}, {RUST$ENUM$DISR = Variant2, __0 = 117901063}} +// gdbr-check:$1 = method_on_enum::Enum::Variant2(117901063) // gdb-command:print arg1 // gdb-check:$2 = -1 // gdb-command:print arg2 @@ -28,7 +29,8 @@ // STACK BY VAL // gdb-command:print self -// gdb-check:$4 = {{RUST$ENUM$DISR = Variant2, [...]}, {RUST$ENUM$DISR = Variant2, __0 = 117901063}} +// gdbg-check:$4 = {{RUST$ENUM$DISR = Variant2, [...]}, {RUST$ENUM$DISR = Variant2, __0 = 117901063}} +// gdbr-check:$4 = method_on_enum::Enum::Variant2(117901063) // gdb-command:print arg1 // gdb-check:$5 = -3 // gdb-command:print arg2 @@ -37,7 +39,8 @@ // OWNED BY REF // gdb-command:print *self -// gdb-check:$7 = {{RUST$ENUM$DISR = Variant1, x = 1799, y = 1799}, {RUST$ENUM$DISR = Variant1, [...]}} +// gdbg-check:$7 = {{RUST$ENUM$DISR = Variant1, x = 1799, y = 1799}, {RUST$ENUM$DISR = Variant1, [...]}} +// gdbr-check:$7 = method_on_enum::Enum::Variant1{x: 1799, y: 1799} // gdb-command:print arg1 // gdb-check:$8 = -5 // gdb-command:print arg2 @@ -46,7 +49,8 @@ // OWNED BY VAL // gdb-command:print self -// gdb-check:$10 = {{RUST$ENUM$DISR = Variant1, x = 1799, y = 1799}, {RUST$ENUM$DISR = Variant1, [...]}} +// gdbg-check:$10 = {{RUST$ENUM$DISR = Variant1, x = 1799, y = 1799}, {RUST$ENUM$DISR = Variant1, [...]}} +// gdbr-check:$10 = method_on_enum::Enum::Variant1{x: 1799, y: 1799} // gdb-command:print arg1 // gdb-check:$11 = -7 // gdb-command:print arg2 @@ -55,7 +59,8 @@ // OWNED MOVED // gdb-command:print *self -// gdb-check:$13 = {{RUST$ENUM$DISR = Variant1, x = 1799, y = 1799}, {RUST$ENUM$DISR = Variant1, [...]}} +// gdbg-check:$13 = {{RUST$ENUM$DISR = Variant1, x = 1799, y = 1799}, {RUST$ENUM$DISR = Variant1, [...]}} +// gdbr-check:$13 = method_on_enum::Enum::Variant1{x: 1799, y: 1799} // gdb-command:print arg1 // gdb-check:$14 = -9 // 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 5b697f859d..20d419b4ac 100644 --- a/src/test/debuginfo/method-on-generic-struct.rs +++ b/src/test/debuginfo/method-on-generic-struct.rs @@ -18,7 +18,8 @@ // STACK BY REF // gdb-command:print *self -// gdb-check:$1 = {x = {__0 = 8888, __1 = -8888}} +// gdbg-check:$1 = {x = {__0 = 8888, __1 = -8888}} +// gdbr-check:$1 = method_on_generic_struct::Struct<(u32, i32)> {x: (8888, -8888)} // gdb-command:print arg1 // gdb-check:$2 = -1 // gdb-command:print arg2 @@ -27,7 +28,8 @@ // STACK BY VAL // gdb-command:print self -// gdb-check:$4 = {x = {__0 = 8888, __1 = -8888}} +// gdbg-check:$4 = {x = {__0 = 8888, __1 = -8888}} +// gdbr-check:$4 = method_on_generic_struct::Struct<(u32, i32)> {x: (8888, -8888)} // gdb-command:print arg1 // gdb-check:$5 = -3 // gdb-command:print arg2 @@ -36,7 +38,8 @@ // OWNED BY REF // gdb-command:print *self -// gdb-check:$7 = {x = 1234.5} +// gdbg-check:$7 = {x = 1234.5} +// gdbr-check:$7 = method_on_generic_struct::Struct {x: 1234.5} // gdb-command:print arg1 // gdb-check:$8 = -5 // gdb-command:print arg2 @@ -45,7 +48,8 @@ // OWNED BY VAL // gdb-command:print self -// gdb-check:$10 = {x = 1234.5} +// gdbg-check:$10 = {x = 1234.5} +// gdbr-check:$10 = method_on_generic_struct::Struct {x: 1234.5} // gdb-command:print arg1 // gdb-check:$11 = -7 // gdb-command:print arg2 @@ -54,7 +58,8 @@ // OWNED MOVED // gdb-command:print *self -// gdb-check:$13 = {x = 1234.5} +// gdbg-check:$13 = {x = 1234.5} +// gdbr-check:$13 = method_on_generic_struct::Struct {x: 1234.5} // gdb-command:print arg1 // gdb-check:$14 = -9 // gdb-command:print arg2 diff --git a/src/test/debuginfo/method-on-struct.rs b/src/test/debuginfo/method-on-struct.rs index 3bf2e775e7..c7546fe222 100644 --- a/src/test/debuginfo/method-on-struct.rs +++ b/src/test/debuginfo/method-on-struct.rs @@ -18,7 +18,8 @@ // STACK BY REF // gdb-command:print *self -// gdb-check:$1 = {x = 100} +// gdbg-check:$1 = {x = 100} +// gdbr-check:$1 = method_on_struct::Struct {x: 100} // gdb-command:print arg1 // gdb-check:$2 = -1 // gdb-command:print arg2 @@ -27,7 +28,8 @@ // STACK BY VAL // gdb-command:print self -// gdb-check:$4 = {x = 100} +// gdbg-check:$4 = {x = 100} +// gdbr-check:$4 = method_on_struct::Struct {x: 100} // gdb-command:print arg1 // gdb-check:$5 = -3 // gdb-command:print arg2 @@ -36,7 +38,8 @@ // OWNED BY REF // gdb-command:print *self -// gdb-check:$7 = {x = 200} +// gdbg-check:$7 = {x = 200} +// gdbr-check:$7 = method_on_struct::Struct {x: 200} // gdb-command:print arg1 // gdb-check:$8 = -5 // gdb-command:print arg2 @@ -45,7 +48,8 @@ // OWNED BY VAL // gdb-command:print self -// gdb-check:$10 = {x = 200} +// gdbg-check:$10 = {x = 200} +// gdbr-check:$10 = method_on_struct::Struct {x: 200} // gdb-command:print arg1 // gdb-check:$11 = -7 // gdb-command:print arg2 @@ -54,7 +58,8 @@ // OWNED MOVED // gdb-command:print *self -// gdb-check:$13 = {x = 200} +// gdbg-check:$13 = {x = 200} +// gdbr-check:$13 = method_on_struct::Struct {x: 200} // gdb-command:print arg1 // gdb-check:$14 = -9 // gdb-command:print arg2 diff --git a/src/test/debuginfo/method-on-trait.rs b/src/test/debuginfo/method-on-trait.rs index 5ce4a7905a..1dc37bb06a 100644 --- a/src/test/debuginfo/method-on-trait.rs +++ b/src/test/debuginfo/method-on-trait.rs @@ -18,7 +18,8 @@ // STACK BY REF // gdb-command:print *self -// gdb-check:$1 = {x = 100} +// gdbg-check:$1 = {x = 100} +// gdbr-check:$1 = method_on_trait::Struct {x: 100} // gdb-command:print arg1 // gdb-check:$2 = -1 // gdb-command:print arg2 @@ -27,7 +28,8 @@ // STACK BY VAL // gdb-command:print self -// gdb-check:$4 = {x = 100} +// gdbg-check:$4 = {x = 100} +// gdbr-check:$4 = method_on_trait::Struct {x: 100} // gdb-command:print arg1 // gdb-check:$5 = -3 // gdb-command:print arg2 @@ -36,7 +38,8 @@ // OWNED BY REF // gdb-command:print *self -// gdb-check:$7 = {x = 200} +// gdbg-check:$7 = {x = 200} +// gdbr-check:$7 = method_on_trait::Struct {x: 200} // gdb-command:print arg1 // gdb-check:$8 = -5 // gdb-command:print arg2 @@ -45,7 +48,8 @@ // OWNED BY VAL // gdb-command:print self -// gdb-check:$10 = {x = 200} +// gdbg-check:$10 = {x = 200} +// gdbr-check:$10 = method_on_trait::Struct {x: 200} // gdb-command:print arg1 // gdb-check:$11 = -7 // gdb-command:print arg2 @@ -54,7 +58,8 @@ // OWNED MOVED // gdb-command:print *self -// gdb-check:$13 = {x = 200} +// gdbg-check:$13 = {x = 200} +// gdbr-check:$13 = method_on_trait::Struct {x: 200} // gdb-command:print arg1 // gdb-check:$14 = -9 // 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 d8644a3934..dac762ae0c 100644 --- a/src/test/debuginfo/method-on-tuple-struct.rs +++ b/src/test/debuginfo/method-on-tuple-struct.rs @@ -18,7 +18,8 @@ // STACK BY REF // gdb-command:print *self -// gdb-check:$1 = {__0 = 100, __1 = -100.5} +// gdbg-check:$1 = {__0 = 100, __1 = -100.5} +// gdbr-check:$1 = method_on_tuple_struct::TupleStruct (100, -100.5) // gdb-command:print arg1 // gdb-check:$2 = -1 // gdb-command:print arg2 @@ -27,7 +28,8 @@ // STACK BY VAL // gdb-command:print self -// gdb-check:$4 = {__0 = 100, __1 = -100.5} +// gdbg-check:$4 = {__0 = 100, __1 = -100.5} +// gdbr-check:$4 = method_on_tuple_struct::TupleStruct (100, -100.5) // gdb-command:print arg1 // gdb-check:$5 = -3 // gdb-command:print arg2 @@ -36,7 +38,8 @@ // OWNED BY REF // gdb-command:print *self -// gdb-check:$7 = {__0 = 200, __1 = -200.5} +// gdbg-check:$7 = {__0 = 200, __1 = -200.5} +// gdbr-check:$7 = method_on_tuple_struct::TupleStruct (200, -200.5) // gdb-command:print arg1 // gdb-check:$8 = -5 // gdb-command:print arg2 @@ -45,7 +48,8 @@ // OWNED BY VAL // gdb-command:print self -// gdb-check:$10 = {__0 = 200, __1 = -200.5} +// gdbg-check:$10 = {__0 = 200, __1 = -200.5} +// gdbr-check:$10 = method_on_tuple_struct::TupleStruct (200, -200.5) // gdb-command:print arg1 // gdb-check:$11 = -7 // gdb-command:print arg2 @@ -54,7 +58,8 @@ // OWNED MOVED // gdb-command:print *self -// gdb-check:$13 = {__0 = 200, __1 = -200.5} +// gdbg-check:$13 = {__0 = 200, __1 = -200.5} +// gdbr-check:$13 = method_on_tuple_struct::TupleStruct (200, -200.5) // gdb-command:print arg1 // gdb-check:$14 = -9 // gdb-command:print arg2 diff --git a/src/test/debuginfo/nil-enum.rs b/src/test/debuginfo/nil-enum.rs index 81399ec590..94377421c0 100644 --- a/src/test/debuginfo/nil-enum.rs +++ b/src/test/debuginfo/nil-enum.rs @@ -16,10 +16,12 @@ // gdb-command:run // gdb-command:print first -// gdb-check:$1 = {} +// gdbg-check:$1 = {} +// gdbr-check:$1 = // gdb-command:print second -// gdb-check:$2 = {} +// gdbg-check:$2 = {} +// gdbr-check:$2 = #![allow(unused_variables)] #![feature(omit_gdb_pretty_printer_section)] @@ -28,8 +30,9 @@ enum ANilEnum {} enum AnotherNilEnum {} -// This test relies on gdb printing the string "{}" for empty +// This test relies on gdbg printing the string "{}" for empty // structs (which may change some time) +// The error from gdbr is expected since nil enums are not supposed to exist. fn main() { unsafe { let first: ANilEnum = ::std::mem::zeroed(); diff --git a/src/test/debuginfo/option-like-enum.rs b/src/test/debuginfo/option-like-enum.rs index f103294a94..39e6a4e4fa 100644 --- a/src/test/debuginfo/option-like-enum.rs +++ b/src/test/debuginfo/option-like-enum.rs @@ -18,28 +18,36 @@ // gdb-command:run // gdb-command:print some -// gdb-check:$1 = {RUST$ENCODED$ENUM$0$None = {__0 = 0x12345678}} +// gdbg-check:$1 = {RUST$ENCODED$ENUM$0$None = {__0 = 0x12345678}} +// gdbr-check:$1 = core::option::Option<&u32>::Some(0x12345678) // gdb-command:print none -// gdb-check:$2 = {RUST$ENCODED$ENUM$0$None = {__0 = 0x0}} +// gdbg-check:$2 = {RUST$ENCODED$ENUM$0$None = {__0 = 0x0}} +// gdbr-check:$2 = core::option::Option<&u32>::None // gdb-command:print full -// gdb-check:$3 = {RUST$ENCODED$ENUM$1$Empty = {__0 = 454545, __1 = 0x87654321, __2 = 9988}} +// gdbg-check:$3 = {RUST$ENCODED$ENUM$1$Empty = {__0 = 454545, __1 = 0x87654321, __2 = 9988}} +// gdbr-check:$3 = option_like_enum::MoreFields::Full(454545, 0x87654321, 9988) -// gdb-command:print empty_gdb->discr +// gdbg-command:print empty_gdb->discr +// gdbr-command:print empty_gdb.discr // gdb-check:$4 = (isize *) 0x0 // gdb-command:print droid -// gdb-check:$5 = {RUST$ENCODED$ENUM$2$Void = {id = 675675, range = 10000001, internals = 0x43218765}} +// gdbg-check:$5 = {RUST$ENCODED$ENUM$2$Void = {id = 675675, range = 10000001, internals = 0x43218765}} +// gdbr-check:$5 = option_like_enum::NamedFields::Droid{id: 675675, range: 10000001, internals: 0x43218765} -// gdb-command:print void_droid_gdb->internals +// gdbg-command:print void_droid_gdb->internals +// gdbr-command:print void_droid_gdb.internals // gdb-check:$6 = (isize *) 0x0 // gdb-command:print nested_non_zero_yep -// gdb-check:$7 = {RUST$ENCODED$ENUM$1$2$Nope = {__0 = 10.5, __1 = {a = 10, b = 20, c = [...]}}} +// gdbg-check:$7 = {RUST$ENCODED$ENUM$1$2$Nope = {__0 = 10.5, __1 = {a = 10, b = 20, c = [...]}}} +// gdbr-check:$7 = option_like_enum::NestedNonZero::Yep(10.5, option_like_enum::NestedNonZeroField {a: 10, b: 20, c: 0x[...] "x[...]"}) // gdb-command:print nested_non_zero_nope -// gdb-check:$8 = {RUST$ENCODED$ENUM$1$2$Nope = {__0 = [...], __1 = {a = [...], b = [...], c = 0x0}}} +// gdbg-check:$8 = {RUST$ENCODED$ENUM$1$2$Nope = {__0 = [...], __1 = {a = [...], b = [...], c = 0x0}}} +// gdbr-check:$8 = option_like_enum::NestedNonZero::Nope // gdb-command:continue diff --git a/src/test/debuginfo/packed-struct-with-destructor.rs b/src/test/debuginfo/packed-struct-with-destructor.rs index 9d37cb3012..50bd857d46 100644 --- a/src/test/debuginfo/packed-struct-with-destructor.rs +++ b/src/test/debuginfo/packed-struct-with-destructor.rs @@ -18,29 +18,37 @@ // gdb-command:run // gdb-command:print packed -// gdb-check:$1 = {x = 123, y = 234, z = 345} +// gdbg-check:$1 = {x = 123, y = 234, z = 345} +// gdbr-check:$1 = packed_struct_with_destructor::Packed {x: 123, y: 234, z: 345} // gdb-command:print packedInPacked -// gdb-check:$2 = {a = 1111, b = {x = 2222, y = 3333, z = 4444}, c = 5555, d = {x = 6666, y = 7777, z = 8888}} +// gdbg-check:$2 = {a = 1111, b = {x = 2222, y = 3333, z = 4444}, c = 5555, d = {x = 6666, y = 7777, z = 8888}} +// gdbr-check:$2 = packed_struct_with_destructor::PackedInPacked {a: 1111, b: packed_struct_with_destructor::Packed {x: 2222, y: 3333, z: 4444}, c: 5555, d: packed_struct_with_destructor::Packed {x: 6666, y: 7777, z: 8888}} // gdb-command:print packedInUnpacked -// gdb-check:$3 = {a = -1111, b = {x = -2222, y = -3333, z = -4444}, c = -5555, d = {x = -6666, y = -7777, z = -8888}} +// gdbg-check:$3 = {a = -1111, b = {x = -2222, y = -3333, z = -4444}, c = -5555, d = {x = -6666, y = -7777, z = -8888}} +// gdbr-check:$3 = packed_struct_with_destructor::PackedInUnpacked {a: -1111, b: packed_struct_with_destructor::Packed {x: -2222, y: -3333, z: -4444}, c: -5555, d: packed_struct_with_destructor::Packed {x: -6666, y: -7777, z: -8888}} // gdb-command:print unpackedInPacked -// gdb-check:$4 = {a = 987, b = {x = 876, y = 765, z = 654}, c = {x = 543, y = 432, z = 321}, d = 210} +// gdbg-check:$4 = {a = 987, b = {x = 876, y = 765, z = 654}, c = {x = 543, y = 432, z = 321}, d = 210} +// gdbr-check:$4 = packed_struct_with_destructor::UnpackedInPacked {a: 987, b: packed_struct_with_destructor::Unpacked {x: 876, y: 765, z: 654}, c: packed_struct_with_destructor::Unpacked {x: 543, y: 432, z: 321}, d: 210} // gdb-command:print packedInPackedWithDrop -// gdb-check:$5 = {a = 11, b = {x = 22, y = 33, z = 44}, c = 55, d = {x = 66, y = 77, z = 88}} +// gdbg-check:$5 = {a = 11, b = {x = 22, y = 33, z = 44}, c = 55, d = {x = 66, y = 77, z = 88}} +// gdbr-check:$5 = packed_struct_with_destructor::PackedInPackedWithDrop {a: 11, b: packed_struct_with_destructor::Packed {x: 22, y: 33, z: 44}, c: 55, d: packed_struct_with_destructor::Packed {x: 66, y: 77, z: 88}} // gdb-command:print packedInUnpackedWithDrop -// gdb-check:$6 = {a = -11, b = {x = -22, y = -33, z = -44}, c = -55, d = {x = -66, y = -77, z = -88}} +// gdbg-check:$6 = {a = -11, b = {x = -22, y = -33, z = -44}, c = -55, d = {x = -66, y = -77, z = -88}} +// gdbr-check:$6 = packed_struct_with_destructor::PackedInUnpackedWithDrop {a: -11, b: packed_struct_with_destructor::Packed {x: -22, y: -33, z: -44}, c: -55, d: packed_struct_with_destructor::Packed {x: -66, y: -77, z: -88}} // gdb-command:print unpackedInPackedWithDrop -// gdb-check:$7 = {a = 98, b = {x = 87, y = 76, z = 65}, c = {x = 54, y = 43, z = 32}, d = 21} +// gdbg-check:$7 = {a = 98, b = {x = 87, y = 76, z = 65}, c = {x = 54, y = 43, z = 32}, d = 21} +// gdbr-check:$7 = packed_struct_with_destructor::UnpackedInPackedWithDrop {a: 98, b: packed_struct_with_destructor::Unpacked {x: 87, y: 76, z: 65}, c: packed_struct_with_destructor::Unpacked {x: 54, y: 43, z: 32}, d: 21} // gdb-command:print deeplyNested -// gdb-check:$8 = {a = {a = 1, b = {x = 2, y = 3, z = 4}, c = 5, d = {x = 6, y = 7, z = 8}}, b = {a = 9, b = {x = 10, y = 11, z = 12}, c = {x = 13, y = 14, z = 15}, d = 16}, c = {a = 17, b = {x = 18, y = 19, z = 20}, c = 21, d = {x = 22, y = 23, z = 24}}, d = {a = 25, b = {x = 26, y = 27, z = 28}, c = 29, d = {x = 30, y = 31, z = 32}}, e = {a = 33, b = {x = 34, y = 35, z = 36}, c = {x = 37, y = 38, z = 39}, d = 40}, f = {a = 41, b = {x = 42, y = 43, z = 44}, c = 45, d = {x = 46, y = 47, z = 48}}} +// gdbg-check:$8 = {a = {a = 1, b = {x = 2, y = 3, z = 4}, c = 5, d = {x = 6, y = 7, z = 8}}, b = {a = 9, b = {x = 10, y = 11, z = 12}, c = {x = 13, y = 14, z = 15}, d = 16}, c = {a = 17, b = {x = 18, y = 19, z = 20}, c = 21, d = {x = 22, y = 23, z = 24}}, d = {a = 25, b = {x = 26, y = 27, z = 28}, c = 29, d = {x = 30, y = 31, z = 32}}, e = {a = 33, b = {x = 34, y = 35, z = 36}, c = {x = 37, y = 38, z = 39}, d = 40}, f = {a = 41, b = {x = 42, y = 43, z = 44}, c = 45, d = {x = 46, y = 47, z = 48}}} +// gdbr-check:$8 = packed_struct_with_destructor::DeeplyNested {a: packed_struct_with_destructor::PackedInPacked {a: 1, b: packed_struct_with_destructor::Packed {x: 2, y: 3, z: 4}, c: 5, d: packed_struct_with_destructor::Packed {x: 6, y: 7, z: 8}}, b: packed_struct_with_destructor::UnpackedInPackedWithDrop {a: 9, b: packed_struct_with_destructor::Unpacked {x: 10, y: 11, z: 12}, c: packed_struct_with_destructor::Unpacked {x: 13, y: 14, z: 15}, d: 16}, c: packed_struct_with_destructor::PackedInUnpacked {a: 17, b: packed_struct_with_destructor::Packed {x: 18, y: 19, z: 20}, c: 21, d: packed_struct_with_destructor::Packed {x: 22, y: 23, z: 24}}, d: packed_struct_with_destructor::PackedInUnpackedWithDrop {a: 25, b: packed_struct_with_destructor::Packed {x: 26, y: 27, z: 28}, c: 29, d: packed_struct_with_destructor::Packed {x: 30, y: 31, z: 32}}, e: packed_struct_with_destructor::UnpackedInPacked {a: 33, b: packed_struct_with_destructor::Unpacked {x: 34, y: 35, z: 36}, c: packed_struct_with_destructor::Unpacked {x: 37, y: 38, z: 39}, d: 40}, f: packed_struct_with_destructor::PackedInPackedWithDrop {a: 41, b: packed_struct_with_destructor::Packed {x: 42, y: 43, z: 44}, c: 45, d: packed_struct_with_destructor::Packed {x: 46, y: 47, z: 48}}} // === LLDB TESTS ================================================================================== diff --git a/src/test/debuginfo/packed-struct.rs b/src/test/debuginfo/packed-struct.rs index e86e963f38..b84161c36a 100644 --- a/src/test/debuginfo/packed-struct.rs +++ b/src/test/debuginfo/packed-struct.rs @@ -18,16 +18,20 @@ // gdb-command:run // gdb-command:print packed -// gdb-check:$1 = {x = 123, y = 234, z = 345} +// gdbg-check:$1 = {x = 123, y = 234, z = 345} +// gdbr-check:$1 = packed_struct::Packed {x: 123, y: 234, z: 345} // gdb-command:print packedInPacked -// gdb-check:$2 = {a = 1111, b = {x = 2222, y = 3333, z = 4444}, c = 5555, d = {x = 6666, y = 7777, z = 8888}} +// gdbg-check:$2 = {a = 1111, b = {x = 2222, y = 3333, z = 4444}, c = 5555, d = {x = 6666, y = 7777, z = 8888}} +// gdbr-check:$2 = packed_struct::PackedInPacked {a: 1111, b: packed_struct::Packed {x: 2222, y: 3333, z: 4444}, c: 5555, d: packed_struct::Packed {x: 6666, y: 7777, z: 8888}} // gdb-command:print packedInUnpacked -// gdb-check:$3 = {a = -1111, b = {x = -2222, y = -3333, z = -4444}, c = -5555, d = {x = -6666, y = -7777, z = -8888}} +// gdbg-check:$3 = {a = -1111, b = {x = -2222, y = -3333, z = -4444}, c = -5555, d = {x = -6666, y = -7777, z = -8888}} +// gdbr-check:$3 = packed_struct::PackedInUnpacked {a: -1111, b: packed_struct::Packed {x: -2222, y: -3333, z: -4444}, c: -5555, d: packed_struct::Packed {x: -6666, y: -7777, z: -8888}} // gdb-command:print unpackedInPacked -// gdb-check:$4 = {a = 987, b = {x = 876, y = 765, z = 654, w = 543}, c = {x = 432, y = 321, z = 210, w = 109}, d = -98} +// gdbg-check:$4 = {a = 987, b = {x = 876, y = 765, z = 654, w = 543}, c = {x = 432, y = 321, z = 210, w = 109}, d = -98} +// gdbr-check:$4 = packed_struct::UnpackedInPacked {a: 987, b: packed_struct::Unpacked {x: 876, y: 765, z: 654, w: 543}, c: packed_struct::Unpacked {x: 432, y: 321, z: 210, w: 109}, d: -98} // gdb-command:print sizeof(packed) // gdb-check:$5 = 14 diff --git a/src/test/debuginfo/pretty-std.rs b/src/test/debuginfo/pretty-std.rs index 576621737e..153f0c8271 100644 --- a/src/test/debuginfo/pretty-std.rs +++ b/src/test/debuginfo/pretty-std.rs @@ -35,7 +35,8 @@ // gdb-check:$5 = Some = {8} // gdb-command: print none -// gdb-check:$6 = None +// gdbg-check:$6 = None +// gdbr-check:$6 = core::option::Option::None // === LLDB TESTS ================================================================================== diff --git a/src/test/debuginfo/recursive-struct.rs b/src/test/debuginfo/recursive-struct.rs index ea067d5bff..80147b1417 100644 --- a/src/test/debuginfo/recursive-struct.rs +++ b/src/test/debuginfo/recursive-struct.rs @@ -12,57 +12,72 @@ // ignore-lldb // compile-flags:-g + // gdb-command:run // gdb-command:print stack_unique.value // gdb-check:$1 = 0 -// gdb-command:print stack_unique.next.RUST$ENCODED$ENUM$0$Empty.val->value +// gdbg-command:print stack_unique.next.RUST$ENCODED$ENUM$0$Empty.val->value +// gdbr-command:print stack_unique.next.val.value // gdb-check:$2 = 1 -// gdb-command:print unique_unique->value +// gdbg-command:print unique_unique->value +// gdbr-command:print unique_unique.value // gdb-check:$3 = 2 -// gdb-command:print unique_unique->next.RUST$ENCODED$ENUM$0$Empty.val->value +// gdbg-command:print unique_unique->next.RUST$ENCODED$ENUM$0$Empty.val->value +// gdbr-command:print unique_unique.next.val.value // gdb-check:$4 = 3 // gdb-command:print vec_unique[0].value // gdb-check:$5 = 6.5 -// gdb-command:print vec_unique[0].next.RUST$ENCODED$ENUM$0$Empty.val->value +// gdbg-command:print vec_unique[0].next.RUST$ENCODED$ENUM$0$Empty.val->value +// gdbr-command:print vec_unique[0].next.val.value // gdb-check:$6 = 7.5 -// gdb-command:print borrowed_unique->value +// gdbg-command:print borrowed_unique->value +// gdbr-command:print borrowed_unique.value // gdb-check:$7 = 8.5 -// gdb-command:print borrowed_unique->next.RUST$ENCODED$ENUM$0$Empty.val->value +// gdbg-command:print borrowed_unique->next.RUST$ENCODED$ENUM$0$Empty.val->value +// gdbr-command:print borrowed_unique.next.val.value // gdb-check:$8 = 9.5 // LONG CYCLE // gdb-command:print long_cycle1.value // gdb-check:$9 = 20 -// gdb-command:print long_cycle1.next->value +// gdbg-command:print long_cycle1.next->value +// gdbr-command:print long_cycle1.next.value // gdb-check:$10 = 21 -// gdb-command:print long_cycle1.next->next->value +// gdbg-command:print long_cycle1.next->next->value +// gdbr-command:print long_cycle1.next.next.value // gdb-check:$11 = 22 -// gdb-command:print long_cycle1.next->next->next->value +// gdbg-command:print long_cycle1.next->next->next->value +// gdbr-command:print long_cycle1.next.next.next.value // gdb-check:$12 = 23 // gdb-command:print long_cycle2.value // gdb-check:$13 = 24 -// gdb-command:print long_cycle2.next->value +// gdbg-command:print long_cycle2.next->value +// gdbr-command:print long_cycle2.next.value // gdb-check:$14 = 25 -// gdb-command:print long_cycle2.next->next->value +// gdbg-command:print long_cycle2.next->next->value +// gdbr-command:print long_cycle2.next.next.value // gdb-check:$15 = 26 // gdb-command:print long_cycle3.value // gdb-check:$16 = 27 -// gdb-command:print long_cycle3.next->value +// gdbg-command:print long_cycle3.next->value +// gdbr-command:print long_cycle3.next.value // gdb-check:$17 = 28 // gdb-command:print long_cycle4.value // gdb-check:$18 = 29.5 -// gdb-command:print (*****long_cycle_w_anonymous_types).value +// gdbg-command:print (*****long_cycle_w_anonymous_types).value +// gdbr-command:print long_cycle_w_anonymous_types.value // gdb-check:$19 = 30 -// gdb-command:print (*****((*****long_cycle_w_anonymous_types).next.RUST$ENCODED$ENUM$0$Empty.val)).value +// gdbg-command:print (*****((*****long_cycle_w_anonymous_types).next.RUST$ENCODED$ENUM$0$Empty.val)).value +// gdbr-command:print long_cycle_w_anonymous_types.next.val.value // gdb-check:$20 = 31 // gdb-command:continue diff --git a/src/test/debuginfo/self-in-default-method.rs b/src/test/debuginfo/self-in-default-method.rs index 6d3f93c5d5..796d122cd6 100644 --- a/src/test/debuginfo/self-in-default-method.rs +++ b/src/test/debuginfo/self-in-default-method.rs @@ -18,7 +18,8 @@ // STACK BY REF // gdb-command:print *self -// gdb-check:$1 = {x = 100} +// gdbg-check:$1 = {x = 100} +// gdbr-check:$1 = self_in_default_method::Struct {x: 100} // gdb-command:print arg1 // gdb-check:$2 = -1 // gdb-command:print arg2 @@ -27,7 +28,8 @@ // STACK BY VAL // gdb-command:print self -// gdb-check:$4 = {x = 100} +// gdbg-check:$4 = {x = 100} +// gdbr-check:$4 = self_in_default_method::Struct {x: 100} // gdb-command:print arg1 // gdb-check:$5 = -3 // gdb-command:print arg2 @@ -36,7 +38,8 @@ // OWNED BY REF // gdb-command:print *self -// gdb-check:$7 = {x = 200} +// gdbg-check:$7 = {x = 200} +// gdbr-check:$7 = self_in_default_method::Struct {x: 200} // gdb-command:print arg1 // gdb-check:$8 = -5 // gdb-command:print arg2 @@ -45,7 +48,8 @@ // OWNED BY VAL // gdb-command:print self -// gdb-check:$10 = {x = 200} +// gdbg-check:$10 = {x = 200} +// gdbr-check:$10 = self_in_default_method::Struct {x: 200} // gdb-command:print arg1 // gdb-check:$11 = -7 // gdb-command:print arg2 @@ -54,7 +58,8 @@ // OWNED MOVED // gdb-command:print *self -// gdb-check:$13 = {x = 200} +// gdbg-check:$13 = {x = 200} +// gdbr-check:$13 = self_in_default_method::Struct {x: 200} // gdb-command:print arg1 // gdb-check:$14 = -9 // gdb-command:print arg2 diff --git a/src/test/debuginfo/self-in-generic-default-method.rs b/src/test/debuginfo/self-in-generic-default-method.rs index aea3bae4bf..b07d7ca5fb 100644 --- a/src/test/debuginfo/self-in-generic-default-method.rs +++ b/src/test/debuginfo/self-in-generic-default-method.rs @@ -18,7 +18,8 @@ // STACK BY REF // gdb-command:print *self -// gdb-check:$1 = {x = 987} +// gdbg-check:$1 = {x = 987} +// gdbr-check:$1 = self_in_generic_default_method::Struct {x: 987} // gdb-command:print arg1 // gdb-check:$2 = -1 // gdb-command:print arg2 @@ -27,7 +28,8 @@ // STACK BY VAL // gdb-command:print self -// gdb-check:$4 = {x = 987} +// gdbg-check:$4 = {x = 987} +// gdbr-check:$4 = self_in_generic_default_method::Struct {x: 987} // gdb-command:print arg1 // gdb-check:$5 = -3 // gdb-command:print arg2 @@ -36,7 +38,8 @@ // OWNED BY REF // gdb-command:print *self -// gdb-check:$7 = {x = 879} +// gdbg-check:$7 = {x = 879} +// gdbr-check:$7 = self_in_generic_default_method::Struct {x: 879} // gdb-command:print arg1 // gdb-check:$8 = -5 // gdb-command:print arg2 @@ -45,7 +48,8 @@ // OWNED BY VAL // gdb-command:print self -// gdb-check:$10 = {x = 879} +// gdbg-check:$10 = {x = 879} +// gdbr-check:$10 = self_in_generic_default_method::Struct {x: 879} // gdb-command:print arg1 // gdb-check:$11 = -7 // gdb-command:print arg2 @@ -54,7 +58,8 @@ // OWNED MOVED // gdb-command:print *self -// gdb-check:$13 = {x = 879} +// gdbg-check:$13 = {x = 879} +// gdbr-check:$13 = self_in_generic_default_method::Struct {x: 879} // gdb-command:print arg1 // gdb-check:$14 = -9 // gdb-command:print arg2 diff --git a/src/test/debuginfo/simd.rs b/src/test/debuginfo/simd.rs index 80ac901b60..75e68f7efe 100644 --- a/src/test/debuginfo/simd.rs +++ b/src/test/debuginfo/simd.rs @@ -20,28 +20,46 @@ // compile-flags:-g // gdb-command:run -// gdb-command:print/d vi8x16 -// 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 = {__0 = 16, __1 = 17, __2 = 18, __3 = 19, __4 = 20, __5 = 21, __6 = 22, __7 = 23} -// gdb-command:print/d vi32x4 -// gdb-check:$3 = {__0 = 24, __1 = 25, __2 = 26, __3 = 27} -// gdb-command:print/d vi64x2 -// gdb-check:$4 = {__0 = 28, __1 = 29} - -// gdb-command:print/d vu8x16 -// 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 = {__0 = 46, __1 = 47, __2 = 48, __3 = 49, __4 = 50, __5 = 51, __6 = 52, __7 = 53} -// gdb-command:print/d vu32x4 -// gdb-check:$7 = {__0 = 54, __1 = 55, __2 = 56, __3 = 57} -// gdb-command:print/d vu64x2 -// gdb-check:$8 = {__0 = 58, __1 = 59} +// gdbg-command:print/d vi8x16 +// gdbr-command:print vi8x16 +// gdbg-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} +// gdbr-check:$1 = simd::i8x16 (0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15) +// gdbg-command:print/d vi16x8 +// gdbr-command:print vi16x8 +// gdbg-check:$2 = {__0 = 16, __1 = 17, __2 = 18, __3 = 19, __4 = 20, __5 = 21, __6 = 22, __7 = 23} +// gdbr-check:$2 = simd::i16x8 (16, 17, 18, 19, 20, 21, 22, 23) +// gdbg-command:print/d vi32x4 +// gdbr-command:print vi32x4 +// gdbg-check:$3 = {__0 = 24, __1 = 25, __2 = 26, __3 = 27} +// gdbr-check:$3 = simd::i32x4 (24, 25, 26, 27) +// gdbg-command:print/d vi64x2 +// gdbr-command:print vi64x2 +// gdbg-check:$4 = {__0 = 28, __1 = 29} +// gdbr-check:$4 = simd::i64x2 (28, 29) + +// gdbg-command:print/d vu8x16 +// gdbr-command:print vu8x16 +// gdbg-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} +// gdbr-check:$5 = simd::u8x16 (30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45) +// gdbg-command:print/d vu16x8 +// gdbr-command:print vu16x8 +// gdbg-check:$6 = {__0 = 46, __1 = 47, __2 = 48, __3 = 49, __4 = 50, __5 = 51, __6 = 52, __7 = 53} +// gdbr-check:$6 = simd::u16x8 (46, 47, 48, 49, 50, 51, 52, 53) +// gdbg-command:print/d vu32x4 +// gdbr-command:print vu32x4 +// gdbg-check:$7 = {__0 = 54, __1 = 55, __2 = 56, __3 = 57} +// gdbr-check:$7 = simd::u32x4 (54, 55, 56, 57) +// gdbg-command:print/d vu64x2 +// gdbr-command:print vu64x2 +// gdbg-check:$8 = {__0 = 58, __1 = 59} +// gdbr-check:$8 = simd::u64x2 (58, 59) // gdb-command:print vf32x4 -// gdb-check:$9 = {__0 = 60.5, __1 = 61.5, __2 = 62.5, __3 = 63.5} +// gdbg-check:$9 = {__0 = 60.5, __1 = 61.5, __2 = 62.5, __3 = 63.5} +// gdbr-check:$9 = simd::f32x4 (60.5, 61.5, 62.5, 63.5) // gdb-command:print vf64x2 -// gdb-check:$10 = {__0 = 64.5, __1 = 65.5} +// gdbg-check:$10 = {__0 = 64.5, __1 = 65.5} +// gdbr-check:$10 = simd::f64x2 (64.5, 65.5) // gdb-command:continue diff --git a/src/test/debuginfo/simple-struct.rs b/src/test/debuginfo/simple-struct.rs index d25cd4d7c0..4956313ad2 100644 --- a/src/test/debuginfo/simple-struct.rs +++ b/src/test/debuginfo/simple-struct.rs @@ -14,61 +14,94 @@ // === GDB TESTS =================================================================================== -// gdb-command:print 'simple_struct::NO_PADDING_16' -// gdb-check:$1 = {x = 1000, y = -1001} - -// gdb-command:print 'simple_struct::NO_PADDING_32' -// gdb-check:$2 = {x = 1, y = 2, z = 3} - -// gdb-command:print 'simple_struct::NO_PADDING_64' -// gdb-check:$3 = {x = 4, y = 5, z = 6} - -// gdb-command:print 'simple_struct::NO_PADDING_163264' -// gdb-check:$4 = {a = 7, b = 8, c = 9, d = 10} - -// gdb-command:print 'simple_struct::INTERNAL_PADDING' -// gdb-check:$5 = {x = 11, y = 12} - -// gdb-command:print 'simple_struct::PADDING_AT_END' -// gdb-check:$6 = {x = 13, y = 14} +// there's no frame yet for gdb to reliably detect the language, set it explicitly +// gdbr-command:set language rust + +// gdbg-command:print 'simple_struct::NO_PADDING_16' +// gdbr-command:print simple_struct::NO_PADDING_16 +// gdbg-check:$1 = {x = 1000, y = -1001} +// gdbr-check:$1 = simple_struct::NoPadding16 {x: 1000, y: -1001} + +// gdbg-command:print 'simple_struct::NO_PADDING_32' +// gdbr-command:print simple_struct::NO_PADDING_32 +// gdbg-check:$2 = {x = 1, y = 2, z = 3} +// gdbr-check:$2 = simple_struct::NoPadding32 {x: 1, y: 2, z: 3} + +// gdbg-command:print 'simple_struct::NO_PADDING_64' +// gdbr-command:print simple_struct::NO_PADDING_64 +// gdbg-check:$3 = {x = 4, y = 5, z = 6} +// gdbr-check:$3 = simple_struct::NoPadding64 {x: 4, y: 5, z: 6} + +// gdbg-command:print 'simple_struct::NO_PADDING_163264' +// gdbr-command:print simple_struct::NO_PADDING_163264 +// gdbg-check:$4 = {a = 7, b = 8, c = 9, d = 10} +// gdbr-check:$4 = simple_struct::NoPadding163264 {a: 7, b: 8, c: 9, d: 10} + +// gdbg-command:print 'simple_struct::INTERNAL_PADDING' +// gdbr-command:print simple_struct::INTERNAL_PADDING +// gdbg-check:$5 = {x = 11, y = 12} +// gdbr-check:$5 = simple_struct::InternalPadding {x: 11, y: 12} + +// gdbg-command:print 'simple_struct::PADDING_AT_END' +// gdbr-command:print simple_struct::PADDING_AT_END +// gdbg-check:$6 = {x = 13, y = 14} +// gdbr-check:$6 = simple_struct::PaddingAtEnd {x: 13, y: 14} // gdb-command:run // gdb-command:print no_padding16 -// gdb-check:$7 = {x = 10000, y = -10001} +// gdbg-check:$7 = {x = 10000, y = -10001} +// gdbr-check:$7 = simple_struct::NoPadding16 {x: 10000, y: -10001} // gdb-command:print no_padding32 -// gdb-check:$8 = {x = -10002, y = -10003.5, z = 10004} +// gdbg-check:$8 = {x = -10002, y = -10003.5, z = 10004} +// gdbr-check:$8 = simple_struct::NoPadding32 {x: -10002, y: -10003.5, z: 10004} // gdb-command:print no_padding64 -// gdb-check:$9 = {x = -10005.5, y = 10006, z = 10007} +// gdbg-check:$9 = {x = -10005.5, y = 10006, z = 10007} +// gdbr-check:$9 = simple_struct::NoPadding64 {x: -10005.5, y: 10006, z: 10007} // gdb-command:print no_padding163264 -// gdb-check:$10 = {a = -10008, b = 10009, c = 10010, d = 10011} +// gdbg-check:$10 = {a = -10008, b = 10009, c = 10010, d = 10011} +// gdbr-check:$10 = simple_struct::NoPadding163264 {a: -10008, b: 10009, c: 10010, d: 10011} // gdb-command:print internal_padding -// gdb-check:$11 = {x = 10012, y = -10013} +// gdbg-check:$11 = {x = 10012, y = -10013} +// gdbr-check:$11 = simple_struct::InternalPadding {x: 10012, y: -10013} // gdb-command:print padding_at_end -// gdb-check:$12 = {x = -10014, y = 10015} - -// gdb-command:print 'simple_struct::NO_PADDING_16' -// gdb-check:$13 = {x = 100, y = -101} - -// gdb-command:print 'simple_struct::NO_PADDING_32' -// gdb-check:$14 = {x = -15, y = -16, z = 17} - -// gdb-command:print 'simple_struct::NO_PADDING_64' -// gdb-check:$15 = {x = -18, y = 19, z = 20} - -// gdb-command:print 'simple_struct::NO_PADDING_163264' -// gdb-check:$16 = {a = -21, b = 22, c = 23, d = 24} - -// gdb-command:print 'simple_struct::INTERNAL_PADDING' -// gdb-check:$17 = {x = 25, y = -26} - -// gdb-command:print 'simple_struct::PADDING_AT_END' -// gdb-check:$18 = {x = -27, y = 28} +// gdbg-check:$12 = {x = -10014, y = 10015} +// gdbr-check:$12 = simple_struct::PaddingAtEnd {x: -10014, y: 10015} + +// gdbg-command:print 'simple_struct::NO_PADDING_16' +// gdbr-command:print simple_struct::NO_PADDING_16 +// gdbg-check:$13 = {x = 100, y = -101} +// gdbr-check:$13 = simple_struct::NoPadding16 {x: 100, y: -101} + +// gdbg-command:print 'simple_struct::NO_PADDING_32' +// gdbr-command:print simple_struct::NO_PADDING_32 +// gdbg-check:$14 = {x = -15, y = -16, z = 17} +// gdbr-check:$14 = simple_struct::NoPadding32 {x: -15, y: -16, z: 17} + +// gdbg-command:print 'simple_struct::NO_PADDING_64' +// gdbr-command:print simple_struct::NO_PADDING_64 +// gdbg-check:$15 = {x = -18, y = 19, z = 20} +// gdbr-check:$15 = simple_struct::NoPadding64 {x: -18, y: 19, z: 20} + +// gdbg-command:print 'simple_struct::NO_PADDING_163264' +// gdbr-command:print simple_struct::NO_PADDING_163264 +// gdbg-check:$16 = {a = -21, b = 22, c = 23, d = 24} +// gdbr-check:$16 = simple_struct::NoPadding163264 {a: -21, b: 22, c: 23, d: 24} + +// gdbg-command:print 'simple_struct::INTERNAL_PADDING' +// gdbr-command:print simple_struct::INTERNAL_PADDING +// gdbg-check:$17 = {x = 25, y = -26} +// gdbr-check:$17 = simple_struct::InternalPadding {x: 25, y: -26} + +// gdbg-command:print 'simple_struct::PADDING_AT_END' +// gdbr-command:print simple_struct::PADDING_AT_END +// gdbg-check:$18 = {x = -27, y = 28} +// gdbr-check:$18 = simple_struct::PaddingAtEnd {x: -27, y: 28} // gdb-command:continue diff --git a/src/test/debuginfo/simple-tuple.rs b/src/test/debuginfo/simple-tuple.rs index 1b85ecc537..354a2c26cb 100644 --- a/src/test/debuginfo/simple-tuple.rs +++ b/src/test/debuginfo/simple-tuple.rs @@ -14,58 +14,97 @@ // === GDB TESTS =================================================================================== -// gdb-command:print/d 'simple_tuple::NO_PADDING_8' -// gdb-check:$1 = {__0 = -50, __1 = 50} -// gdb-command:print 'simple_tuple::NO_PADDING_16' -// gdb-check:$2 = {__0 = -1, __1 = 2, __2 = 3} -// gdb-command:print 'simple_tuple::NO_PADDING_32' -// gdb-check:$3 = {__0 = 4, __1 = 5, __2 = 6} -// gdb-command:print 'simple_tuple::NO_PADDING_64' -// gdb-check:$4 = {__0 = 7, __1 = 8, __2 = 9} - -// gdb-command:print 'simple_tuple::INTERNAL_PADDING_1' -// gdb-check:$5 = {__0 = 10, __1 = 11} -// gdb-command:print 'simple_tuple::INTERNAL_PADDING_2' -// gdb-check:$6 = {__0 = 12, __1 = 13, __2 = 14, __3 = 15} - -// gdb-command:print 'simple_tuple::PADDING_AT_END' -// gdb-check:$7 = {__0 = 16, __1 = 17} +// there's no frame yet for gdb to reliably detect the language, set it explicitly +// gdbr-command:set language rust + +// gdbg-command:print/d 'simple_tuple::NO_PADDING_8' +// gdbr-command:print simple_tuple::NO_PADDING_8 +// gdbg-check:$1 = {__0 = -50, __1 = 50} +// gdbr-check:$1 = (-50, 50) +// gdbg-command:print 'simple_tuple::NO_PADDING_16' +// gdbr-command:print simple_tuple::NO_PADDING_16 +// gdbg-check:$2 = {__0 = -1, __1 = 2, __2 = 3} +// gdbr-check:$2 = (-1, 2, 3) +// gdbg-command:print 'simple_tuple::NO_PADDING_32' +// gdbr-command:print simple_tuple::NO_PADDING_32 +// gdbg-check:$3 = {__0 = 4, __1 = 5, __2 = 6} +// gdbr-check:$3 = (4, 5, 6) +// gdbg-command:print 'simple_tuple::NO_PADDING_64' +// gdbr-command:print simple_tuple::NO_PADDING_64 +// gdbg-check:$4 = {__0 = 7, __1 = 8, __2 = 9} +// gdbr-check:$4 = (7, 8, 9) + +// gdbg-command:print 'simple_tuple::INTERNAL_PADDING_1' +// gdbr-command:print simple_tuple::INTERNAL_PADDING_1 +// gdbg-check:$5 = {__0 = 10, __1 = 11} +// gdbr-check:$5 = (10, 11) +// gdbg-command:print 'simple_tuple::INTERNAL_PADDING_2' +// gdbr-command:print simple_tuple::INTERNAL_PADDING_2 +// gdbg-check:$6 = {__0 = 12, __1 = 13, __2 = 14, __3 = 15} +// gdbr-check:$6 = (12, 13, 14, 15) + +// gdbg-command:print 'simple_tuple::PADDING_AT_END' +// gdbr-command:print simple_tuple::PADDING_AT_END +// gdbg-check:$7 = {__0 = 16, __1 = 17} +// gdbr-check:$7 = (16, 17) // gdb-command:run -// gdb-command:print/d noPadding8 -// gdb-check:$8 = {__0 = -100, __1 = 100} +// gdbg-command:print/d noPadding8 +// gdbr-command:print noPadding8 +// gdbg-check:$8 = {__0 = -100, __1 = 100} +// gdbr-check:$8 = (-100, 100) // gdb-command:print noPadding16 -// gdb-check:$9 = {__0 = 0, __1 = 1, __2 = 2} +// gdbg-check:$9 = {__0 = 0, __1 = 1, __2 = 2} +// gdbr-check:$9 = (0, 1, 2) // gdb-command:print noPadding32 -// gdb-check:$10 = {__0 = 3, __1 = 4.5, __2 = 5} +// gdbg-check:$10 = {__0 = 3, __1 = 4.5, __2 = 5} +// gdbr-check:$10 = (3, 4.5, 5) // gdb-command:print noPadding64 -// gdb-check:$11 = {__0 = 6, __1 = 7.5, __2 = 8} +// gdbg-check:$11 = {__0 = 6, __1 = 7.5, __2 = 8} +// gdbr-check:$11 = (6, 7.5, 8) // gdb-command:print internalPadding1 -// gdb-check:$12 = {__0 = 9, __1 = 10} +// gdbg-check:$12 = {__0 = 9, __1 = 10} +// gdbr-check:$12 = (9, 10) // gdb-command:print internalPadding2 -// gdb-check:$13 = {__0 = 11, __1 = 12, __2 = 13, __3 = 14} +// gdbg-check:$13 = {__0 = 11, __1 = 12, __2 = 13, __3 = 14} +// gdbr-check:$13 = (11, 12, 13, 14) // gdb-command:print paddingAtEnd -// gdb-check:$14 = {__0 = 15, __1 = 16} - -// gdb-command:print/d 'simple_tuple::NO_PADDING_8' -// gdb-check:$15 = {__0 = -127, __1 = 127} -// gdb-command:print 'simple_tuple::NO_PADDING_16' -// gdb-check:$16 = {__0 = -10, __1 = 10, __2 = 9} -// gdb-command:print 'simple_tuple::NO_PADDING_32' -// gdb-check:$17 = {__0 = 14, __1 = 15, __2 = 16} -// gdb-command:print 'simple_tuple::NO_PADDING_64' -// gdb-check:$18 = {__0 = 17, __1 = 18, __2 = 19} - -// gdb-command:print 'simple_tuple::INTERNAL_PADDING_1' -// gdb-check:$19 = {__0 = 110, __1 = 111} -// gdb-command:print 'simple_tuple::INTERNAL_PADDING_2' -// gdb-check:$20 = {__0 = 112, __1 = 113, __2 = 114, __3 = 115} - -// gdb-command:print 'simple_tuple::PADDING_AT_END' -// gdb-check:$21 = {__0 = 116, __1 = 117} +// gdbg-check:$14 = {__0 = 15, __1 = 16} +// gdbr-check:$14 = (15, 16) + +// gdbg-command:print/d 'simple_tuple::NO_PADDING_8' +// gdbr-command:print simple_tuple::NO_PADDING_8 +// gdbg-check:$15 = {__0 = -127, __1 = 127} +// gdbr-check:$15 = (-127, 127) +// gdbg-command:print 'simple_tuple::NO_PADDING_16' +// gdbr-command:print simple_tuple::NO_PADDING_16 +// gdbg-check:$16 = {__0 = -10, __1 = 10, __2 = 9} +// gdbr-check:$16 = (-10, 10, 9) +// gdbg-command:print 'simple_tuple::NO_PADDING_32' +// gdbr-command:print simple_tuple::NO_PADDING_32 +// gdbg-check:$17 = {__0 = 14, __1 = 15, __2 = 16} +// gdbr-check:$17 = (14, 15, 16) +// gdbg-command:print 'simple_tuple::NO_PADDING_64' +// gdbr-command:print simple_tuple::NO_PADDING_64 +// gdbg-check:$18 = {__0 = 17, __1 = 18, __2 = 19} +// gdbr-check:$18 = (17, 18, 19) + +// gdbg-command:print 'simple_tuple::INTERNAL_PADDING_1' +// gdbr-command:print simple_tuple::INTERNAL_PADDING_1 +// gdbg-check:$19 = {__0 = 110, __1 = 111} +// gdbr-check:$19 = (110, 111) +// gdbg-command:print 'simple_tuple::INTERNAL_PADDING_2' +// gdbr-command:print simple_tuple::INTERNAL_PADDING_2 +// gdbg-check:$20 = {__0 = 112, __1 = 113, __2 = 114, __3 = 115} +// gdbr-check:$20 = (112, 113, 114, 115) + +// gdbg-command:print 'simple_tuple::PADDING_AT_END' +// gdbr-command:print simple_tuple::PADDING_AT_END +// gdbg-check:$21 = {__0 = 116, __1 = 117} +// gdbr-check:$21 = (116, 117) // === LLDB TESTS ================================================================================== diff --git a/src/test/debuginfo/struct-in-enum.rs b/src/test/debuginfo/struct-in-enum.rs index 98b90de600..d0aceaa4f3 100644 --- a/src/test/debuginfo/struct-in-enum.rs +++ b/src/test/debuginfo/struct-in-enum.rs @@ -19,13 +19,16 @@ // gdb-command:run // gdb-command:print case1 -// 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}} +// gdbg-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}} +// gdbr-check:$1 = struct_in_enum::Regular::Case1(0, struct_in_enum::Struct {x: 2088533116, y: 2088533116, z: 31868}) // gdb-command:print case2 -// 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}} +// gdbg-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}} +// gdbr-check:$2 = struct_in_enum::Regular::Case2(0, 1229782938247303441, 4369) // gdb-command:print univariant -// gdb-check:$3 = {{__0 = {x = 123, y = 456, z = 789}}} +// gdbg-check:$3 = {{__0 = {x = 123, y = 456, z = 789}}} +// gdbr-check:$3 = struct_in_enum::Univariant::TheOnlyCase(struct_in_enum::Struct {x: 123, y: 456, z: 789}) // === LLDB TESTS ================================================================================== diff --git a/src/test/debuginfo/struct-in-struct.rs b/src/test/debuginfo/struct-in-struct.rs index 76a1613c23..46524cf1d0 100644 --- a/src/test/debuginfo/struct-in-struct.rs +++ b/src/test/debuginfo/struct-in-struct.rs @@ -18,13 +18,16 @@ // gdb-command:run // gdb-command:print three_simple_structs -// gdb-check:$1 = {x = {x = 1}, y = {x = 2}, z = {x = 3}} +// gdbg-check:$1 = {x = {x = 1}, y = {x = 2}, z = {x = 3}} +// gdbr-check:$1 = struct_in_struct::ThreeSimpleStructs {x: struct_in_struct::Simple {x: 1}, y: struct_in_struct::Simple {x: 2}, z: struct_in_struct::Simple {x: 3}} // gdb-command:print internal_padding_parent -// gdb-check:$2 = {x = {x = 4, y = 5}, y = {x = 6, y = 7}, z = {x = 8, y = 9}} +// gdbg-check:$2 = {x = {x = 4, y = 5}, y = {x = 6, y = 7}, z = {x = 8, y = 9}} +// gdbr-check:$2 = struct_in_struct::InternalPaddingParent {x: struct_in_struct::InternalPadding {x: 4, y: 5}, y: struct_in_struct::InternalPadding {x: 6, y: 7}, z: struct_in_struct::InternalPadding {x: 8, y: 9}} // gdb-command:print padding_at_end_parent -// gdb-check:$3 = {x = {x = 10, y = 11}, y = {x = 12, y = 13}, z = {x = 14, y = 15}} +// gdbg-check:$3 = {x = {x = 10, y = 11}, y = {x = 12, y = 13}, z = {x = 14, y = 15}} +// gdbr-check:$3 = struct_in_struct::PaddingAtEndParent {x: struct_in_struct::PaddingAtEnd {x: 10, y: 11}, y: struct_in_struct::PaddingAtEnd {x: 12, y: 13}, z: struct_in_struct::PaddingAtEnd {x: 14, y: 15}} // === LLDB TESTS ================================================================================== diff --git a/src/test/debuginfo/struct-style-enum.rs b/src/test/debuginfo/struct-style-enum.rs index 3376fc9bbd..8abc139eb1 100644 --- a/src/test/debuginfo/struct-style-enum.rs +++ b/src/test/debuginfo/struct-style-enum.rs @@ -19,16 +19,20 @@ // gdb-command:run // gdb-command:print case1 -// gdb-check:$1 = {{RUST$ENUM$DISR = Case1, a = 0, b = 31868, c = 31868, d = 31868, e = 31868}, {RUST$ENUM$DISR = Case1, a = 0, b = 2088533116, c = 2088533116}, {RUST$ENUM$DISR = Case1, a = 0, b = 8970181431921507452}} +// gdbg-check:$1 = {{RUST$ENUM$DISR = Case1, a = 0, b = 31868, c = 31868, d = 31868, e = 31868}, {RUST$ENUM$DISR = Case1, a = 0, b = 2088533116, c = 2088533116}, {RUST$ENUM$DISR = Case1, a = 0, b = 8970181431921507452}} +// gdbr-check:$1 = struct_style_enum::Regular::Case1{a: 0, b: 31868, c: 31868, d: 31868, e: 31868} // gdb-command:print case2 -// gdb-check:$2 = {{RUST$ENUM$DISR = Case2, a = 0, b = 4369, c = 4369, d = 4369, e = 4369}, {RUST$ENUM$DISR = Case2, a = 0, b = 286331153, c = 286331153}, {RUST$ENUM$DISR = Case2, a = 0, b = 1229782938247303441}} +// gdbg-check:$2 = {{RUST$ENUM$DISR = Case2, a = 0, b = 4369, c = 4369, d = 4369, e = 4369}, {RUST$ENUM$DISR = Case2, a = 0, b = 286331153, c = 286331153}, {RUST$ENUM$DISR = Case2, a = 0, b = 1229782938247303441}} +// gdbr-check:$2 = struct_style_enum::Regular::Case2{a: 0, b: 286331153, c: 286331153} // gdb-command:print case3 -// gdb-check:$3 = {{RUST$ENUM$DISR = Case3, a = 0, b = 22873, c = 22873, d = 22873, e = 22873}, {RUST$ENUM$DISR = Case3, a = 0, b = 1499027801, c = 1499027801}, {RUST$ENUM$DISR = Case3, a = 0, b = 6438275382588823897}} +// gdbg-check:$3 = {{RUST$ENUM$DISR = Case3, a = 0, b = 22873, c = 22873, d = 22873, e = 22873}, {RUST$ENUM$DISR = Case3, a = 0, b = 1499027801, c = 1499027801}, {RUST$ENUM$DISR = Case3, a = 0, b = 6438275382588823897}} +// gdbr-check:$3 = struct_style_enum::Regular::Case3{a: 0, b: 6438275382588823897} // gdb-command:print univariant -// gdb-check:$4 = {{a = -1}} +// gdbg-check:$4 = {{a = -1}} +// gdbr-check:$4 = struct_style_enum::Univariant::TheOnlyCase{a: -1} // === LLDB TESTS ================================================================================== diff --git a/src/test/debuginfo/struct-with-destructor.rs b/src/test/debuginfo/struct-with-destructor.rs index ad8731997a..af70b4a63f 100644 --- a/src/test/debuginfo/struct-with-destructor.rs +++ b/src/test/debuginfo/struct-with-destructor.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 @@ -16,16 +18,20 @@ // gdb-command:run // gdb-command:print simple -// gdb-check:$1 = {x = 10, y = 20} +// gdbg-check:$1 = {x = 10, y = 20} +// gdbr-check:$1 = struct_with_destructor::WithDestructor {x: 10, y: 20} // gdb-command:print noDestructor -// gdb-check:$2 = {a = {x = 10, y = 20}, guard = -1} +// gdbg-check:$2 = {a = {x = 10, y = 20}, guard = -1} +// gdbr-check:$2 = struct_with_destructor::NoDestructorGuarded {a: struct_with_destructor::NoDestructor {x: 10, y: 20}, guard: -1} // gdb-command:print withDestructor -// gdb-check:$3 = {a = {x = 10, y = 20}, guard = -1} +// gdbg-check:$3 = {a = {x = 10, y = 20}, guard = -1} +// gdbr-check:$3 = struct_with_destructor::WithDestructorGuarded {a: struct_with_destructor::WithDestructor {x: 10, y: 20}, guard: -1} // gdb-command:print nested -// gdb-check:$4 = {a = {a = {x = 7890, y = 9870}}} +// gdbg-check:$4 = {a = {a = {x = 7890, y = 9870}}} +// gdbr-check:$4 = struct_with_destructor::NestedOuter {a: struct_with_destructor::NestedInner {a: struct_with_destructor::WithDestructor {x: 7890, y: 9870}}} // === LLDB TESTS ================================================================================== diff --git a/src/test/debuginfo/tuple-in-struct.rs b/src/test/debuginfo/tuple-in-struct.rs index 1a7fde766f..dae1f5da54 100644 --- a/src/test/debuginfo/tuple-in-struct.rs +++ b/src/test/debuginfo/tuple-in-struct.rs @@ -17,29 +17,39 @@ // gdb-command:run // gdb-command:print no_padding1 -// gdb-check:$1 = {x = {__0 = 0, __1 = 1}, y = 2, z = {__0 = 3, __1 = 4, __2 = 5}} +// gdbg-check:$1 = {x = {__0 = 0, __1 = 1}, y = 2, z = {__0 = 3, __1 = 4, __2 = 5}} +// gdbr-check:$1 = tuple_in_struct::NoPadding1 {x: (0, 1), y: 2, z: (3, 4, 5)} // gdb-command:print no_padding2 -// gdb-check:$2 = {x = {__0 = 6, __1 = 7}, y = {__0 = {__0 = 8, __1 = 9}, __1 = 10}} +// gdbg-check:$2 = {x = {__0 = 6, __1 = 7}, y = {__0 = {__0 = 8, __1 = 9}, __1 = 10}} +// gdbr-check:$2 = tuple_in_struct::NoPadding2 {x: (6, 7), y: ((8, 9), 10)} // gdb-command:print tuple_internal_padding -// gdb-check:$3 = {x = {__0 = 11, __1 = 12}, y = {__0 = 13, __1 = 14}} +// gdbg-check:$3 = {x = {__0 = 11, __1 = 12}, y = {__0 = 13, __1 = 14}} +// gdbr-check:$3 = tuple_in_struct::TupleInternalPadding {x: (11, 12), y: (13, 14)} // gdb-command:print struct_internal_padding -// gdb-check:$4 = {x = {__0 = 15, __1 = 16}, y = {__0 = 17, __1 = 18}} +// gdbg-check:$4 = {x = {__0 = 15, __1 = 16}, y = {__0 = 17, __1 = 18}} +// gdbr-check:$4 = tuple_in_struct::StructInternalPadding {x: (15, 16), y: (17, 18)} // gdb-command:print both_internally_padded -// gdb-check:$5 = {x = {__0 = 19, __1 = 20, __2 = 21}, y = {__0 = 22, __1 = 23}} +// gdbg-check:$5 = {x = {__0 = 19, __1 = 20, __2 = 21}, y = {__0 = 22, __1 = 23}} +// gdbr-check:$5 = tuple_in_struct::BothInternallyPadded {x: (19, 20, 21), y: (22, 23)} // gdb-command:print single_tuple -// gdb-check:$6 = {x = {__0 = 24, __1 = 25, __2 = 26}} +// gdbg-check:$6 = {x = {__0 = 24, __1 = 25, __2 = 26}} +// gdbr-check:$6 = tuple_in_struct::SingleTuple {x: (24, 25, 26)} // gdb-command:print tuple_padded_at_end -// gdb-check:$7 = {x = {__0 = 27, __1 = 28}, y = {__0 = 29, __1 = 30}} +// gdbg-check:$7 = {x = {__0 = 27, __1 = 28}, y = {__0 = 29, __1 = 30}} +// gdbr-check:$7 = tuple_in_struct::TuplePaddedAtEnd {x: (27, 28), y: (29, 30)} // gdb-command:print struct_padded_at_end -// gdb-check:$8 = {x = {__0 = 31, __1 = 32}, y = {__0 = 33, __1 = 34}} +// gdbg-check:$8 = {x = {__0 = 31, __1 = 32}, y = {__0 = 33, __1 = 34}} +// gdbr-check:$8 = tuple_in_struct::StructPaddedAtEnd {x: (31, 32), y: (33, 34)} // gdb-command:print both_padded_at_end -// gdb-check:$9 = {x = {__0 = 35, __1 = 36, __2 = 37}, y = {__0 = 38, __1 = 39}} +// gdbg-check:$9 = {x = {__0 = 35, __1 = 36, __2 = 37}, y = {__0 = 38, __1 = 39}} +// gdbr-check:$9 = tuple_in_struct::BothPaddedAtEnd {x: (35, 36, 37), y: (38, 39)} // gdb-command:print mixed_padding -// 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}} +// gdbg-check:$10 = {x = {__0 = {__0 = 40, __1 = 41, __2 = 42}, __1 = {__0 = 43, __1 = 44}}, y = {__0 = 45, __1 = 46, __2 = 47, __3 = 48}} +// gdbr-check:$10 = tuple_in_struct::MixedPadding {x: ((40, 41, 42), (43, 44)), y: (45, 46, 47, 48)} #![allow(unused_variables)] #![feature(omit_gdb_pretty_printer_section)] diff --git a/src/test/debuginfo/tuple-in-tuple.rs b/src/test/debuginfo/tuple-in-tuple.rs index a514b69a2d..4ebc740b9c 100644 --- a/src/test/debuginfo/tuple-in-tuple.rs +++ b/src/test/debuginfo/tuple-in-tuple.rs @@ -17,21 +17,28 @@ // gdb-command:run // gdb-command:print no_padding1 -// gdb-check:$1 = {__0 = {__0 = 0, __1 = 1}, __1 = 2, __2 = 3} +// gdbg-check:$1 = {__0 = {__0 = 0, __1 = 1}, __1 = 2, __2 = 3} +// gdbr-check:$1 = ((0, 1), 2, 3) // gdb-command:print no_padding2 -// gdb-check:$2 = {__0 = 4, __1 = {__0 = 5, __1 = 6}, __2 = 7} +// gdbg-check:$2 = {__0 = 4, __1 = {__0 = 5, __1 = 6}, __2 = 7} +// gdbr-check:$2 = (4, (5, 6), 7) // gdb-command:print no_padding3 -// gdb-check:$3 = {__0 = 8, __1 = 9, __2 = {__0 = 10, __1 = 11}} +// gdbg-check:$3 = {__0 = 8, __1 = 9, __2 = {__0 = 10, __1 = 11}} +// gdbr-check:$3 = (8, 9, (10, 11)) // gdb-command:print internal_padding1 -// gdb-check:$4 = {__0 = 12, __1 = {__0 = 13, __1 = 14}} +// gdbg-check:$4 = {__0 = 12, __1 = {__0 = 13, __1 = 14}} +// gdbr-check:$4 = (12, (13, 14)) // gdb-command:print internal_padding2 -// gdb-check:$5 = {__0 = 15, __1 = {__0 = 16, __1 = 17}} +// gdbg-check:$5 = {__0 = 15, __1 = {__0 = 16, __1 = 17}} +// gdbr-check:$5 = (15, (16, 17)) // gdb-command:print padding_at_end1 -// gdb-check:$6 = {__0 = 18, __1 = {__0 = 19, __1 = 20}} +// gdbg-check:$6 = {__0 = 18, __1 = {__0 = 19, __1 = 20}} +// gdbr-check:$6 = (18, (19, 20)) // gdb-command:print padding_at_end2 -// gdb-check:$7 = {__0 = {__0 = 21, __1 = 22}, __1 = 23} +// gdbg-check:$7 = {__0 = {__0 = 21, __1 = 22}, __1 = 23} +// gdbr-check:$7 = ((21, 22), 23) // === LLDB TESTS ================================================================================== diff --git a/src/test/debuginfo/tuple-struct.rs b/src/test/debuginfo/tuple-struct.rs index a2ca8c2237..aa644d8419 100644 --- a/src/test/debuginfo/tuple-struct.rs +++ b/src/test/debuginfo/tuple-struct.rs @@ -17,22 +17,28 @@ // gdb-command:run // gdb-command:print no_padding16 -// gdb-check:$1 = {__0 = 10000, __1 = -10001} +// gdbg-check:$1 = {__0 = 10000, __1 = -10001} +// gdbr-check:$1 = tuple_struct::NoPadding16 (10000, -10001) // gdb-command:print no_padding32 -// gdb-check:$2 = {__0 = -10002, __1 = -10003.5, __2 = 10004} +// gdbg-check:$2 = {__0 = -10002, __1 = -10003.5, __2 = 10004} +// gdbr-check:$2 = tuple_struct::NoPadding32 (-10002, -10003.5, 10004) // gdb-command:print no_padding64 -// gdb-check:$3 = {__0 = -10005.5, __1 = 10006, __2 = 10007} +// gdbg-check:$3 = {__0 = -10005.5, __1 = 10006, __2 = 10007} +// gdbr-check:$3 = tuple_struct::NoPadding64 (-10005.5, 10006, 10007) // gdb-command:print no_padding163264 -// gdb-check:$4 = {__0 = -10008, __1 = 10009, __2 = 10010, __3 = 10011} +// gdbg-check:$4 = {__0 = -10008, __1 = 10009, __2 = 10010, __3 = 10011} +// gdbr-check:$4 = tuple_struct::NoPadding163264 (-10008, 10009, 10010, 10011) // gdb-command:print internal_padding -// gdb-check:$5 = {__0 = 10012, __1 = -10013} +// gdbg-check:$5 = {__0 = 10012, __1 = -10013} +// gdbr-check:$5 = tuple_struct::InternalPadding (10012, -10013) // gdb-command:print padding_at_end -// gdb-check:$6 = {__0 = -10014, __1 = 10015} +// gdbg-check:$6 = {__0 = -10014, __1 = 10015} +// gdbr-check:$6 = tuple_struct::PaddingAtEnd (-10014, 10015) // === LLDB TESTS ================================================================================== diff --git a/src/test/debuginfo/tuple-style-enum.rs b/src/test/debuginfo/tuple-style-enum.rs index 52f171434b..d05edec3e7 100644 --- a/src/test/debuginfo/tuple-style-enum.rs +++ b/src/test/debuginfo/tuple-style-enum.rs @@ -19,16 +19,20 @@ // gdb-command:run // gdb-command:print case1 -// 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}} +// gdbg-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}} +// gdbr-check:$1 = tuple_style_enum::Regular::Case1(0, 31868, 31868, 31868, 31868) // gdb-command:print case2 -// 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}} +// gdbg-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}} +// gdbr-check:$2 = tuple_style_enum::Regular::Case2(0, 286331153, 286331153) // gdb-command:print case3 -// 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}} +// gdbg-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}} +// gdbr-check:$3 = tuple_style_enum::Regular::Case3(0, 6438275382588823897) // gdb-command:print univariant -// gdb-check:$4 = {{__0 = -1}} +// gdbg-check:$4 = {{__0 = -1}} +// gdbr-check:$4 = tuple_style_enum::Univariant::TheOnlyCase(-1) // === LLDB TESTS ================================================================================== diff --git a/src/test/debuginfo/type-names.rs b/src/test/debuginfo/type-names.rs index 2419625cbd..438a78743b 100644 --- a/src/test/debuginfo/type-names.rs +++ b/src/test/debuginfo/type-names.rs @@ -20,160 +20,206 @@ // STRUCTS // gdb-command:whatis simple_struct -// gdb-check:type = struct Struct1 +// gdbg-check:type = struct Struct1 +// gdbr-check:type = type_names::Struct1 // gdb-command:whatis generic_struct1 -// gdb-check:type = struct GenericStruct +// gdbg-check:type = struct GenericStruct +// gdbr-check:type = type_names::GenericStruct // gdb-command:whatis generic_struct2 -// gdb-check:type = struct GenericStruct usize> +// gdbg-check:type = struct GenericStruct usize> +// gdbr-check:type = type_names::GenericStruct usize> // gdb-command:whatis mod_struct -// gdb-check:type = struct Struct2 +// gdbg-check:type = struct Struct2 +// gdbr-check:type = type_names::mod1::Struct2 // ENUMS // gdb-command:whatis simple_enum_1 -// gdb-check:type = union Enum1 +// gdbg-check:type = union Enum1 +// gdbr-check:type = type_names::Enum1 // gdb-command:whatis simple_enum_2 -// gdb-check:type = union Enum1 +// gdbg-check:type = union Enum1 +// gdbr-check:type = type_names::Enum1 // gdb-command:whatis simple_enum_3 -// gdb-check:type = union Enum2 +// gdbg-check:type = union Enum2 +// gdbr-check:type = type_names::mod1::Enum2 // gdb-command:whatis generic_enum_1 -// gdb-check:type = union Enum3 +// gdbg-check:type = union Enum3 +// gdbr-check:type = type_names::mod1::mod2::Enum3 // gdb-command:whatis generic_enum_2 -// gdb-check:type = union Enum3 +// gdbg-check:type = union Enum3 +// gdbr-check:type = type_names::mod1::mod2::Enum3 // TUPLES // gdb-command:whatis tuple1 -// gdb-check:type = struct (u32, type_names::Struct1, type_names::mod1::mod2::Enum3) +// gdbg-check:type = struct (u32, type_names::Struct1, type_names::mod1::mod2::Enum3) +// gdbr-check:type = (u32, type_names::Struct1, type_names::mod1::mod2::Enum3) // gdb-command:whatis tuple2 -// gdb-check:type = struct ((type_names::Struct1, type_names::mod1::mod2::Struct3), type_names::mod1::Enum2, char) +// gdbg-check:type = struct ((type_names::Struct1, type_names::mod1::mod2::Struct3), type_names::mod1::Enum2, char) +// gdbr-check:type = ((type_names::Struct1, type_names::mod1::mod2::Struct3), type_names::mod1::Enum2, char) // BOX // gdb-command:whatis box1 -// gdb-check:type = struct (Box, i32) +// gdbg-check:type = struct (Box, i32) +// gdbr-check:type = (Box, i32) // gdb-command:whatis box2 -// gdb-check:type = struct (Box>, i32) +// gdbg-check:type = struct (Box>, i32) +// gdbr-check:type = (Box>, i32) // REFERENCES // gdb-command:whatis ref1 -// gdb-check:type = struct (&type_names::Struct1, i32) +// gdbg-check:type = struct (&type_names::Struct1, i32) +// gdbr-check:type = (&type_names::Struct1, i32) // gdb-command:whatis ref2 -// gdb-check:type = struct (&type_names::GenericStruct, i32) +// gdbg-check:type = struct (&type_names::GenericStruct, i32) +// gdbr-check:type = (&type_names::GenericStruct, i32) // gdb-command:whatis mut_ref1 -// gdb-check:type = struct (&mut type_names::Struct1, i32) +// gdbg-check:type = struct (&mut type_names::Struct1, i32) +// gdbr-check:type = (&mut type_names::Struct1, i32) // gdb-command:whatis mut_ref2 -// gdb-check:type = struct (&mut type_names::GenericStruct, i32) +// gdbg-check:type = struct (&mut type_names::GenericStruct, i32) +// gdbr-check:type = (&mut type_names::GenericStruct, i32) // RAW POINTERS // gdb-command:whatis mut_ptr1 -// gdb-check:type = struct (*mut type_names::Struct1, isize) +// gdbg-check:type = struct (*mut type_names::Struct1, isize) +// gdbr-check:type = (*mut type_names::Struct1, isize) // gdb-command:whatis mut_ptr2 -// gdb-check:type = struct (*mut isize, isize) +// gdbg-check:type = struct (*mut isize, isize) +// gdbr-check:type = (*mut isize, isize) // gdb-command:whatis mut_ptr3 -// gdb-check:type = struct (*mut type_names::mod1::mod2::Enum3, isize) +// gdbg-check:type = struct (*mut type_names::mod1::mod2::Enum3, isize) +// gdbr-check:type = (*mut type_names::mod1::mod2::Enum3, isize) // gdb-command:whatis const_ptr1 -// gdb-check:type = struct (*const type_names::Struct1, isize) +// gdbg-check:type = struct (*const type_names::Struct1, isize) +// gdbr-check:type = (*const type_names::Struct1, isize) // gdb-command:whatis const_ptr2 -// gdb-check:type = struct (*const isize, isize) +// gdbg-check:type = struct (*const isize, isize) +// gdbr-check:type = (*const isize, isize) // gdb-command:whatis const_ptr3 -// gdb-check:type = struct (*const type_names::mod1::mod2::Enum3, isize) +// gdbg-check:type = struct (*const type_names::mod1::mod2::Enum3, isize) +// gdbr-check:type = (*const type_names::mod1::mod2::Enum3, isize) // VECTORS // gdb-command:whatis fixed_size_vec1 -// gdb-check:type = struct ([type_names::Struct1; 3], i16) +// gdbg-check:type = struct ([type_names::Struct1; 3], i16) +// gdbr-check:type = ([type_names::Struct1; 3], i16) // gdb-command:whatis fixed_size_vec2 -// gdb-check:type = struct ([usize; 3], i16) +// gdbg-check:type = struct ([usize; 3], i16) +// gdbr-check:type = ([usize; 3], i16) // gdb-command:whatis slice1 -// gdb-check:type = struct &[usize] +// gdbg-check:type = struct &[usize] +// gdbr-check:type = &[usize] // gdb-command:whatis slice2 -// gdb-check:type = struct &[type_names::mod1::Enum2] +// gdbg-check:type = struct &[type_names::mod1::Enum2] +// gdbr-check:type = &[type_names::mod1::Enum2] // TRAITS // gdb-command:whatis box_trait -// gdb-check:type = struct Box +// gdbg-check:type = struct Box +// gdbr-check:type = type_names::Box // gdb-command:whatis ref_trait -// gdb-check:type = struct &Trait1 +// gdbg-check:type = struct &Trait1 +// gdbr-check:type = type_names::&Trait1 // gdb-command:whatis mut_ref_trait -// gdb-check:type = struct &mut Trait1 +// gdbg-check:type = struct &mut Trait1 +// gdbr-check:type = type_names::&mut Trait1 // gdb-command:whatis generic_box_trait -// gdb-check:type = struct Box> +// gdbg-check:type = struct Box> +// gdbr-check:type = type_names::Box> // gdb-command:whatis generic_ref_trait -// gdb-check:type = struct &Trait2 +// gdbg-check:type = struct &Trait2 +// gdbr-check:type = type_names::&Trait2 // gdb-command:whatis generic_mut_ref_trait -// gdb-check:type = struct &mut Trait2> +// gdbg-check:type = struct &mut Trait2> +// gdbr-check:type = type_names::&mut Trait2> // BARE FUNCTIONS // gdb-command:whatis rust_fn -// gdb-check:type = struct (fn(core::option::Option, core::option::Option<&type_names::mod1::Struct2>), usize) +// gdbg-check:type = struct (fn(core::option::Option, core::option::Option<&type_names::mod1::Struct2>), usize) +// gdbr-check:type = (fn(core::option::Option, core::option::Option<&type_names::mod1::Struct2>), usize) // gdb-command:whatis extern_c_fn -// gdb-check:type = struct (extern "C" fn(isize), usize) +// gdbg-check:type = struct (extern "C" fn(isize), usize) +// gdbr-check:type = (extern "C" fn(isize), usize) // gdb-command:whatis unsafe_fn -// gdb-check:type = struct (unsafe fn(core::result::Result), usize) +// gdbg-check:type = struct (unsafe fn(core::result::Result), usize) +// gdbr-check:type = (unsafe fn(core::result::Result), usize) // gdb-command:whatis extern_stdcall_fn -// gdb-check:type = struct (extern "stdcall" fn(), usize) +// gdbg-check:type = struct (extern "stdcall" fn(), usize) +// gdbr-check:type = (extern "stdcall" fn(), usize) // gdb-command:whatis rust_fn_with_return_value -// gdb-check:type = struct (fn(f64) -> usize, usize) +// gdbg-check:type = struct (fn(f64) -> usize, usize) +// gdbr-check:type = (fn(f64) -> usize, usize) // gdb-command:whatis extern_c_fn_with_return_value -// gdb-check:type = struct (extern "C" fn() -> type_names::Struct1, usize) +// gdbg-check:type = struct (extern "C" fn() -> type_names::Struct1, usize) +// gdbr-check:type = (extern "C" fn() -> type_names::Struct1, usize) // gdb-command:whatis unsafe_fn_with_return_value -// gdb-check:type = struct (unsafe fn(type_names::GenericStruct) -> type_names::mod1::Struct2, usize) +// gdbg-check:type = struct (unsafe fn(type_names::GenericStruct) -> type_names::mod1::Struct2, usize) +// gdbr-check:type = (unsafe fn(type_names::GenericStruct) -> type_names::mod1::Struct2, usize) // gdb-command:whatis extern_stdcall_fn_with_return_value -// gdb-check:type = struct (extern "stdcall" fn(Box) -> usize, usize) +// gdbg-check:type = struct (extern "stdcall" fn(Box) -> usize, usize) +// gdbr-check:type = (extern "stdcall" fn(Box) -> usize, usize) // gdb-command:whatis generic_function_int -// gdb-check:type = struct (fn(isize) -> isize, usize) +// gdbg-check:type = struct (fn(isize) -> isize, usize) +// gdbr-check:type = (fn(isize) -> isize, usize) // gdb-command:whatis generic_function_struct3 -// gdb-check:type = struct (fn(type_names::mod1::mod2::Struct3) -> type_names::mod1::mod2::Struct3, usize) +// gdbg-check:type = struct (fn(type_names::mod1::mod2::Struct3) -> type_names::mod1::mod2::Struct3, usize) +// gdbr-check:type = (fn(type_names::mod1::mod2::Struct3) -> type_names::mod1::mod2::Struct3, usize) // gdb-command:whatis variadic_function -// gdb-check:type = struct (unsafe extern "C" fn(*const u8, ...) -> isize, usize) +// gdbg-check:type = struct (unsafe extern "C" fn(*const u8, ...) -> isize, usize) +// gdbr-check:type = (unsafe extern "C" fn(*const u8, ...) -> isize, usize) // CLOSURES // gdb-command:whatis closure1 -// gdb-check:type = struct (closure, usize) +// gdbg-check:type = struct (closure, usize) +// gdbr-check:type = (closure, usize) // gdb-command:whatis closure2 -// gdb-check:type = struct (closure, usize) +// gdbg-check:type = struct (closure, usize) +// gdbr-check:type = (closure, usize) #![feature(box_syntax)] #![allow(unused_variables)] diff --git a/src/test/debuginfo/union-smoke.rs b/src/test/debuginfo/union-smoke.rs index 319927c979..26e73a08ea 100644 --- a/src/test/debuginfo/union-smoke.rs +++ b/src/test/debuginfo/union-smoke.rs @@ -16,9 +16,11 @@ // gdb-command:run // gdb-command:print u -// gdb-check:$1 = {a = {__0 = 2 '\002', __1 = 2 '\002'}, b = 514} +// gdbg-check:$1 = {a = {__0 = 2 '\002', __1 = 2 '\002'}, b = 514} +// gdbr-check:$1 = union_smoke::U {a: (2, 2), b: 514} // gdb-command:print union_smoke::SU -// gdb-check:$2 = {a = {__0 = 1 '\001', __1 = 1 '\001'}, b = 257} +// gdbg-check:$2 = {a = {__0 = 1 '\001', __1 = 1 '\001'}, b = 257} +// gdbr-check:$2 = union_smoke::U {a: (1, 1), b: 257} // === LLDB TESTS ================================================================================== diff --git a/src/test/debuginfo/unique-enum.rs b/src/test/debuginfo/unique-enum.rs index bbf13ec756..e882544b80 100644 --- a/src/test/debuginfo/unique-enum.rs +++ b/src/test/debuginfo/unique-enum.rs @@ -18,13 +18,16 @@ // gdb-command:run // gdb-command:print *the_a -// gdb-check:$1 = {{RUST$ENUM$DISR = TheA, x = 0, y = 8970181431921507452}, {RUST$ENUM$DISR = TheA, __0 = 0, __1 = 2088533116, __2 = 2088533116}} +// gdbg-check:$1 = {{RUST$ENUM$DISR = TheA, x = 0, y = 8970181431921507452}, {RUST$ENUM$DISR = TheA, __0 = 0, __1 = 2088533116, __2 = 2088533116}} +// gdbr-check:$1 = unique_enum::ABC::TheA{x: 0, y: 8970181431921507452} // gdb-command:print *the_b -// gdb-check:$2 = {{RUST$ENUM$DISR = TheB, x = 0, y = 1229782938247303441}, {RUST$ENUM$DISR = TheB, __0 = 0, __1 = 286331153, __2 = 286331153}} +// gdbg-check:$2 = {{RUST$ENUM$DISR = TheB, x = 0, y = 1229782938247303441}, {RUST$ENUM$DISR = TheB, __0 = 0, __1 = 286331153, __2 = 286331153}} +// gdbr-check:$2 = unique_enum::ABC::TheB(0, 286331153, 286331153) // gdb-command:print *univariant -// gdb-check:$3 = {{__0 = 123234}} +// gdbg-check:$3 = {{__0 = 123234}} +// gdbr-check:$3 = unique_enum::Univariant::TheOnlyCase(123234) // === LLDB TESTS ================================================================================== diff --git a/src/test/debuginfo/var-captured-in-nested-closure.rs b/src/test/debuginfo/var-captured-in-nested-closure.rs index 7090377e5d..b9a1d73b6d 100644 --- a/src/test/debuginfo/var-captured-in-nested-closure.rs +++ b/src/test/debuginfo/var-captured-in-nested-closure.rs @@ -21,9 +21,11 @@ // gdb-command:print constant // gdb-check:$2 = 2 // gdb-command:print a_struct -// gdb-check:$3 = {a = -3, b = 4.5, c = 5} +// gdbg-check:$3 = {a = -3, b = 4.5, c = 5} +// gdbr-check:$3 = var_captured_in_nested_closure::Struct {a: -3, b: 4.5, c: 5} // gdb-command:print *struct_ref -// gdb-check:$4 = {a = -3, b = 4.5, c = 5} +// gdbg-check:$4 = {a = -3, b = 4.5, c = 5} +// gdbr-check:$4 = var_captured_in_nested_closure::Struct {a: -3, b: 4.5, c: 5} // gdb-command:print *owned // gdb-check:$5 = 6 // gdb-command:print closure_local @@ -35,9 +37,11 @@ // gdb-command:print constant // gdb-check:$8 = 2 // gdb-command:print a_struct -// gdb-check:$9 = {a = -3, b = 4.5, c = 5} +// gdbg-check:$9 = {a = -3, b = 4.5, c = 5} +// gdbr-check:$9 = var_captured_in_nested_closure::Struct {a: -3, b: 4.5, c: 5} // gdb-command:print *struct_ref -// gdb-check:$10 = {a = -3, b = 4.5, c = 5} +// gdbg-check:$10 = {a = -3, b = 4.5, c = 5} +// gdbr-check:$10 = var_captured_in_nested_closure::Struct {a: -3, b: 4.5, c: 5} // gdb-command:print *owned // gdb-check:$11 = 6 // gdb-command:print closure_local diff --git a/src/test/debuginfo/var-captured-in-sendable-closure.rs b/src/test/debuginfo/var-captured-in-sendable-closure.rs index b415546fae..120bbdd7ba 100644 --- a/src/test/debuginfo/var-captured-in-sendable-closure.rs +++ b/src/test/debuginfo/var-captured-in-sendable-closure.rs @@ -19,7 +19,8 @@ // gdb-command:print constant // gdb-check:$1 = 1 // gdb-command:print a_struct -// gdb-check:$2 = {a = -2, b = 3.5, c = 4} +// gdbg-check:$2 = {a = -2, b = 3.5, c = 4} +// gdbr-check:$2 = var_captured_in_sendable_closure::Struct {a: -2, b: 3.5, c: 4} // gdb-command:print *owned // gdb-check:$3 = 5 // gdb-command:continue diff --git a/src/test/debuginfo/var-captured-in-stack-closure.rs b/src/test/debuginfo/var-captured-in-stack-closure.rs index e60f964dd0..c795a095b9 100644 --- a/src/test/debuginfo/var-captured-in-stack-closure.rs +++ b/src/test/debuginfo/var-captured-in-stack-closure.rs @@ -21,9 +21,11 @@ // gdb-command:print constant // gdb-check:$2 = 2 // gdb-command:print a_struct -// gdb-check:$3 = {a = -3, b = 4.5, c = 5} +// gdbg-check:$3 = {a = -3, b = 4.5, c = 5} +// gdbr-check:$3 = var_captured_in_stack_closure::Struct {a: -3, b: 4.5, c: 5} // gdb-command:print *struct_ref -// gdb-check:$4 = {a = -3, b = 4.5, c = 5} +// gdbg-check:$4 = {a = -3, b = 4.5, c = 5} +// gdbr-check:$4 = var_captured_in_stack_closure::Struct {a: -3, b: 4.5, c: 5} // gdb-command:print *owned // gdb-check:$5 = 6 @@ -34,9 +36,11 @@ // gdb-command:print constant // gdb-check:$7 = 2 // gdb-command:print a_struct -// gdb-check:$8 = {a = -3, b = 4.5, c = 5} +// gdbg-check:$8 = {a = -3, b = 4.5, c = 5} +// gdbr-check:$8 = var_captured_in_stack_closure::Struct {a: -3, b: 4.5, c: 5} // gdb-command:print *struct_ref -// gdb-check:$9 = {a = -3, b = 4.5, c = 5} +// gdbg-check:$9 = {a = -3, b = 4.5, c = 5} +// gdbr-check:$9 = var_captured_in_stack_closure::Struct {a: -3, b: 4.5, c: 5} // gdb-command:print *owned // gdb-check:$10 = 6 diff --git a/src/test/debuginfo/vec-slices.rs b/src/test/debuginfo/vec-slices.rs index cdb5bc4ecf..5553f8427e 100644 --- a/src/test/debuginfo/vec-slices.rs +++ b/src/test/debuginfo/vec-slices.rs @@ -21,42 +21,57 @@ // gdb-command:print singleton.length // gdb-check:$2 = 1 -// gdb-command:print *((int64_t[1]*)(singleton.data_ptr)) -// gdb-check:$3 = {1} +// gdbg-command:print *((int64_t[1]*)(singleton.data_ptr)) +// gdbr-command:print *(singleton.data_ptr as &[i64; 1]) +// gdbg-check:$3 = {1} +// gdbr-check:$3 = [1] // gdb-command:print multiple.length // gdb-check:$4 = 4 -// gdb-command:print *((int64_t[4]*)(multiple.data_ptr)) -// gdb-check:$5 = {2, 3, 4, 5} +// gdbg-command:print *((int64_t[4]*)(multiple.data_ptr)) +// gdbr-command:print *(multiple.data_ptr as &[i64; 4]) +// gdbg-check:$5 = {2, 3, 4, 5} +// gdbr-check:$5 = [2, 3, 4, 5] // gdb-command:print slice_of_slice.length // gdb-check:$6 = 2 -// gdb-command:print *((int64_t[2]*)(slice_of_slice.data_ptr)) -// gdb-check:$7 = {3, 4} +// gdbg-command:print *((int64_t[2]*)(slice_of_slice.data_ptr)) +// gdbr-command:print *(slice_of_slice.data_ptr as &[i64; 2]) +// gdbg-check:$7 = {3, 4} +// gdbr-check:$7 = [3, 4] // gdb-command:print padded_tuple.length // gdb-check:$8 = 2 // gdb-command:print padded_tuple.data_ptr[0] -// gdb-check:$9 = {__0 = 6, __1 = 7} +// gdbg-check:$9 = {__0 = 6, __1 = 7} +// gdbr-check:$9 = (6, 7) // gdb-command:print padded_tuple.data_ptr[1] -// gdb-check:$10 = {__0 = 8, __1 = 9} +// gdbg-check:$10 = {__0 = 8, __1 = 9} +// gdbr-check:$10 = (8, 9) // gdb-command:print padded_struct.length // gdb-check:$11 = 2 // gdb-command:print padded_struct.data_ptr[0] -// gdb-check:$12 = {x = 10, y = 11, z = 12} +// gdbg-check:$12 = {x = 10, y = 11, z = 12} +// gdbr-check:$12 = vec_slices::AStruct {x: 10, y: 11, z: 12} // gdb-command:print padded_struct.data_ptr[1] -// gdb-check:$13 = {x = 13, y = 14, z = 15} +// gdbg-check:$13 = {x = 13, y = 14, z = 15} +// gdbr-check:$13 = vec_slices::AStruct {x: 13, y: 14, z: 15} -// gdb-command:print 'vec_slices::MUT_VECT_SLICE'.length +// gdbg-command:print 'vec_slices::MUT_VECT_SLICE'.length +// gdbr-command:print MUT_VECT_SLICE.length // gdb-check:$14 = 2 -// gdb-command:print *((int64_t[2]*)('vec_slices::MUT_VECT_SLICE'.data_ptr)) -// gdb-check:$15 = {64, 65} +// gdbg-command:print *((int64_t[2]*)('vec_slices::MUT_VECT_SLICE'.data_ptr)) +// gdbr-command:print *(MUT_VECT_SLICE.data_ptr as &[i64; 2]) +// gdbg-check:$15 = {64, 65} +// gdbr-check:$15 = [64, 65] //gdb-command:print mut_slice.length //gdb-check:$16 = 5 -//gdb-command:print *((int64_t[5]*)(mut_slice.data_ptr)) -//gdb-check:$17 = {1, 2, 3, 4, 5} +//gdbg-command:print *((int64_t[5]*)(mut_slice.data_ptr)) +//gdbr-command:print *(mut_slice.data_ptr as &[i64; 5]) +//gdbg-check:$17 = {1, 2, 3, 4, 5} +//gdbr-check:$17 = [1, 2, 3, 4, 5] // === LLDB TESTS ================================================================================== diff --git a/src/test/debuginfo/vec.rs b/src/test/debuginfo/vec.rs index c9827a02fc..fbb33b94d9 100644 --- a/src/test/debuginfo/vec.rs +++ b/src/test/debuginfo/vec.rs @@ -16,9 +16,11 @@ // gdb-command:run // gdb-command:print a -// gdb-check:$1 = {1, 2, 3} +// gdbg-check:$1 = {1, 2, 3} +// gdbr-check:$1 = [1, 2, 3] // gdb-command:print vec::VECT -// gdb-check:$2 = {4, 5, 6} +// gdbg-check:$2 = {4, 5, 6} +// gdbr-check:$2 = [4, 5, 6] // === LLDB TESTS ================================================================================== diff --git a/src/test/run-pass/lint-non-uppercase-statics-lowercase-mut-statics.rs b/src/test/incremental/change_crate_order/auxiliary/a.rs similarity index 65% rename from src/test/run-pass/lint-non-uppercase-statics-lowercase-mut-statics.rs rename to src/test/incremental/change_crate_order/auxiliary/a.rs index aa5b3834c0..69b4acd3e3 100644 --- a/src/test/run-pass/lint-non-uppercase-statics-lowercase-mut-statics.rs +++ b/src/test/incremental/change_crate_order/auxiliary/a.rs @@ -1,4 +1,4 @@ -// Copyright 2013 The Rust Project Developers. See the COPYRIGHT +// 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. // @@ -8,12 +8,7 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. +#![crate_type="rlib"] -// pretty-expanded FIXME #23616 +pub static A : u32 = 32; -#![forbid(non_camel_case_types)] -#![forbid(non_upper_case_globals)] - -static mut bar: isize = 2; - -pub fn main() {} diff --git a/src/test/incremental/change_crate_order/auxiliary/b.rs b/src/test/incremental/change_crate_order/auxiliary/b.rs new file mode 100644 index 0000000000..1ab97a312c --- /dev/null +++ b/src/test/incremental/change_crate_order/auxiliary/b.rs @@ -0,0 +1,14 @@ +// 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. + +#![crate_type="rlib"] + +pub static B: u32 = 32; + diff --git a/src/test/incremental/change_crate_order/main.rs b/src/test/incremental/change_crate_order/main.rs new file mode 100644 index 0000000000..bd8742ff38 --- /dev/null +++ b/src/test/incremental/change_crate_order/main.rs @@ -0,0 +1,34 @@ +// 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. + +// aux-build:a.rs +// aux-build:b.rs +// revisions:rpass1 rpass2 + +#![feature(rustc_attrs)] + + +#[cfg(rpass1)] +extern crate a; +#[cfg(rpass1)] +extern crate b; + +#[cfg(rpass2)] +extern crate b; +#[cfg(rpass2)] +extern crate a; + +use a::A; +use b::B; + +//? #[rustc_clean(label="TypeckItemBody", cfg="rpass2")] +pub fn main() { + A + B; +} diff --git a/src/test/incremental/change_private_fn/struct_point.rs b/src/test/incremental/change_private_fn/struct_point.rs new file mode 100644 index 0000000000..678bc10f1e --- /dev/null +++ b/src/test/incremental/change_private_fn/struct_point.rs @@ -0,0 +1,111 @@ +// 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 where we change the body of a private method in an impl. +// We then test what sort of functions must be rebuilt as a result. + +// revisions:rpass1 rpass2 +// compile-flags: -Z query-dep-graph + +#![feature(rustc_attrs)] +#![feature(stmt_expr_attributes)] +#![allow(dead_code)] + +#![rustc_partition_translated(module="struct_point-point", cfg="rpass2")] + +#![rustc_partition_reused(module="struct_point-fn_calls_methods_in_same_impl", cfg="rpass2")] +#![rustc_partition_reused(module="struct_point-fn_calls_methods_in_another_impl", cfg="rpass2")] +#![rustc_partition_reused(module="struct_point-fn_make_struct", cfg="rpass2")] +#![rustc_partition_reused(module="struct_point-fn_read_field", cfg="rpass2")] +#![rustc_partition_reused(module="struct_point-fn_write_field", cfg="rpass2")] + +mod point { + pub struct Point { + pub x: f32, + pub y: f32, + } + + fn distance_squared(this: &Point) -> f32 { + #[cfg(rpass1)] + return this.x + this.y; + + #[cfg(rpass2)] + return this.x * this.x + this.y * this.y; + } + + impl Point { + pub fn distance_from_origin(&self) -> f32 { + distance_squared(self).sqrt() + } + } + + impl Point { + pub fn translate(&mut self, x: f32, y: f32) { + self.x += x; + self.y += y; + } + } + +} + +/// A fn item that calls (public) methods on `Point` from the same impl which changed +mod fn_calls_methods_in_same_impl { + use point::Point; + + #[rustc_clean(label="TypeckItemBody", cfg="rpass2")] + pub fn check() { + let x = Point { x: 2.0, y: 2.0 }; + x.distance_from_origin(); + } +} + +/// A fn item that calls (public) methods on `Point` from another impl +mod fn_calls_methods_in_another_impl { + use point::Point; + + #[rustc_clean(label="TypeckItemBody", cfg="rpass2")] + pub fn check() { + let mut x = Point { x: 2.0, y: 2.0 }; + x.translate(3.0, 3.0); + } +} + +/// A fn item that makes an instance of `Point` but does not invoke methods +mod fn_make_struct { + use point::Point; + + #[rustc_clean(label="TypeckItemBody", cfg="rpass2")] + pub fn make_origin() -> Point { + Point { x: 2.0, y: 2.0 } + } +} + +/// A fn item that reads fields from `Point` but does not invoke methods +mod fn_read_field { + use point::Point; + + #[rustc_clean(label="TypeckItemBody", cfg="rpass2")] + pub fn get_x(p: Point) -> f32 { + p.x + } +} + +/// A fn item that writes to a field of `Point` but does not invoke methods +mod fn_write_field { + use point::Point; + + #[rustc_clean(label="TypeckItemBody", cfg="rpass2")] + pub fn inc_x(p: &mut Point) { + p.x += 1.0; + } +} + +fn main() { +} diff --git a/src/test/incremental/change_private_fn_cc/auxiliary/point.rs b/src/test/incremental/change_private_fn_cc/auxiliary/point.rs new file mode 100644 index 0000000000..dcc1ced635 --- /dev/null +++ b/src/test/incremental/change_private_fn_cc/auxiliary/point.rs @@ -0,0 +1,35 @@ +// 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. + +pub struct Point { + pub x: f32, + pub y: f32, +} + +fn distance_squared(this: &Point) -> f32 { + #[cfg(rpass1)] + return this.x + this.y; + + #[cfg(rpass2)] + return this.x * this.x + this.y * this.y; +} + +impl Point { + pub fn distance_from_origin(&self) -> f32 { + distance_squared(self).sqrt() + } +} + +impl Point { + pub fn translate(&mut self, x: f32, y: f32) { + self.x += x; + self.y += y; + } +} diff --git a/src/test/incremental/change_private_fn_cc/struct_point.rs b/src/test/incremental/change_private_fn_cc/struct_point.rs new file mode 100644 index 0000000000..d6d2b5436f --- /dev/null +++ b/src/test/incremental/change_private_fn_cc/struct_point.rs @@ -0,0 +1,86 @@ +// 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 where we change the body of a private method in an impl. +// We then test what sort of functions must be rebuilt as a result. + +// revisions:rpass1 rpass2 +// compile-flags: -Z query-dep-graph +// aux-build:point.rs + +#![feature(rustc_attrs)] +#![feature(stmt_expr_attributes)] +#![allow(dead_code)] + +#![rustc_partition_reused(module="struct_point-fn_calls_methods_in_same_impl", cfg="rpass2")] +#![rustc_partition_reused(module="struct_point-fn_calls_methods_in_another_impl", cfg="rpass2")] +#![rustc_partition_reused(module="struct_point-fn_read_field", cfg="rpass2")] +#![rustc_partition_reused(module="struct_point-fn_write_field", cfg="rpass2")] + +// FIXME(#37335) -- should be reused, but an errant Krate edge causes +// it to get translated (at least I *think* this is that same problem) +#![rustc_partition_translated(module="struct_point-fn_make_struct", cfg="rpass2")] + +extern crate point; + +/// A fn item that calls (public) methods on `Point` from the same impl which changed +mod fn_calls_methods_in_same_impl { + use point::Point; + + #[rustc_clean(label="TypeckItemBody", cfg="rpass2")] + pub fn check() { + let x = Point { x: 2.0, y: 2.0 }; + x.distance_from_origin(); + } +} + +/// A fn item that calls (public) methods on `Point` from another impl +mod fn_calls_methods_in_another_impl { + use point::Point; + + #[rustc_clean(label="TypeckItemBody", cfg="rpass2")] + pub fn check() { + let mut x = Point { x: 2.0, y: 2.0 }; + x.translate(3.0, 3.0); + } +} + +/// A fn item that makes an instance of `Point` but does not invoke methods +mod fn_make_struct { + use point::Point; + + #[rustc_clean(label="TypeckItemBody", cfg="rpass2")] + pub fn make_origin() -> Point { + Point { x: 2.0, y: 2.0 } + } +} + +/// A fn item that reads fields from `Point` but does not invoke methods +mod fn_read_field { + use point::Point; + + #[rustc_clean(label="TypeckItemBody", cfg="rpass2")] + pub fn get_x(p: Point) -> f32 { + p.x + } +} + +/// A fn item that writes to a field of `Point` but does not invoke methods +mod fn_write_field { + use point::Point; + + #[rustc_clean(label="TypeckItemBody", cfg="rpass2")] + pub fn inc_x(p: &mut Point) { + p.x += 1.0; + } +} + +fn main() { +} diff --git a/src/test/incremental/change_private_impl_method/struct_point.rs b/src/test/incremental/change_private_impl_method/struct_point.rs new file mode 100644 index 0000000000..8fa34bde17 --- /dev/null +++ b/src/test/incremental/change_private_impl_method/struct_point.rs @@ -0,0 +1,114 @@ +// 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 where we change the body of a private method in an impl. +// We then test what sort of functions must be rebuilt as a result. + +// revisions:rpass1 rpass2 +// compile-flags: -Z query-dep-graph + +#![feature(rustc_attrs)] +#![feature(stmt_expr_attributes)] +#![allow(dead_code)] + +#![rustc_partition_translated(module="struct_point-point", cfg="rpass2")] + +// FIXME(#37121) -- the following two modules *should* be reused but are not +#![rustc_partition_translated(module="struct_point-fn_calls_methods_in_same_impl", cfg="rpass2")] +#![rustc_partition_translated(module="struct_point-fn_calls_methods_in_another_impl", cfg="rpass2")] +#![rustc_partition_reused(module="struct_point-fn_make_struct", cfg="rpass2")] +#![rustc_partition_reused(module="struct_point-fn_read_field", cfg="rpass2")] +#![rustc_partition_reused(module="struct_point-fn_write_field", cfg="rpass2")] + +mod point { + pub struct Point { + pub x: f32, + pub y: f32, + } + + impl Point { + fn distance_squared(&self) -> f32 { + #[cfg(rpass1)] + return self.x + self.y; + + #[cfg(rpass2)] + return self.x * self.x + self.y * self.y; + } + + pub fn distance_from_origin(&self) -> f32 { + self.distance_squared().sqrt() + } + } + + impl Point { + pub fn translate(&mut self, x: f32, y: f32) { + self.x += x; + self.y += y; + } + } + +} + +/// A fn item that calls (public) methods on `Point` from the same impl which changed +mod fn_calls_methods_in_same_impl { + use point::Point; + + // FIXME(#37121) -- we should not need to typeck this again + #[rustc_dirty(label="TypeckItemBody", cfg="rpass2")] + pub fn check() { + let x = Point { x: 2.0, y: 2.0 }; + x.distance_from_origin(); + } +} + +/// A fn item that calls (public) methods on `Point` from another impl +mod fn_calls_methods_in_another_impl { + use point::Point; + + // FIXME(#37121) -- we should not need to typeck this again + #[rustc_dirty(label="TypeckItemBody", cfg="rpass2")] + pub fn check() { + let mut x = Point { x: 2.0, y: 2.0 }; + x.translate(3.0, 3.0); + } +} + +/// A fn item that makes an instance of `Point` but does not invoke methods +mod fn_make_struct { + use point::Point; + + #[rustc_clean(label="TypeckItemBody", cfg="rpass2")] + pub fn make_origin() -> Point { + Point { x: 2.0, y: 2.0 } + } +} + +/// A fn item that reads fields from `Point` but does not invoke methods +mod fn_read_field { + use point::Point; + + #[rustc_clean(label="TypeckItemBody", cfg="rpass2")] + pub fn get_x(p: Point) -> f32 { + p.x + } +} + +/// A fn item that writes to a field of `Point` but does not invoke methods +mod fn_write_field { + use point::Point; + + #[rustc_clean(label="TypeckItemBody", cfg="rpass2")] + pub fn inc_x(p: &mut Point) { + p.x += 1.0; + } +} + +fn main() { +} diff --git a/src/test/incremental/change_private_impl_method_cc/auxiliary/point.rs b/src/test/incremental/change_private_impl_method_cc/auxiliary/point.rs new file mode 100644 index 0000000000..8df1cf54da --- /dev/null +++ b/src/test/incremental/change_private_impl_method_cc/auxiliary/point.rs @@ -0,0 +1,35 @@ +// 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. + +pub struct Point { + pub x: f32, + pub y: f32, +} + +impl Point { + fn distance_squared(&self) -> f32 { + #[cfg(rpass1)] + return self.x + self.y; + + #[cfg(rpass2)] + return self.x * self.x + self.y * self.y; + } + + pub fn distance_from_origin(&self) -> f32 { + self.distance_squared().sqrt() + } +} + +impl Point { + pub fn translate(&mut self, x: f32, y: f32) { + self.x += x; + self.y += y; + } +} diff --git a/src/test/incremental/change_private_impl_method_cc/struct_point.rs b/src/test/incremental/change_private_impl_method_cc/struct_point.rs new file mode 100644 index 0000000000..d8e5fbadad --- /dev/null +++ b/src/test/incremental/change_private_impl_method_cc/struct_point.rs @@ -0,0 +1,89 @@ +// 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 where we change the body of a private method in an impl. +// We then test what sort of functions must be rebuilt as a result. + +// revisions:rpass1 rpass2 +// compile-flags: -Z query-dep-graph +// aux-build:point.rs + +#![feature(rustc_attrs)] +#![feature(stmt_expr_attributes)] +#![allow(dead_code)] + +// FIXME(#37333) -- the following modules *should* be reused but are not +#![rustc_partition_translated(module="struct_point-fn_calls_methods_in_same_impl", cfg="rpass2")] +#![rustc_partition_translated(module="struct_point-fn_calls_methods_in_another_impl", cfg="rpass2")] +#![rustc_partition_translated(module="struct_point-fn_make_struct", cfg="rpass2")] +#![rustc_partition_translated(module="struct_point-fn_read_field", cfg="rpass2")] +#![rustc_partition_translated(module="struct_point-fn_write_field", cfg="rpass2")] + +extern crate point; + +/// A fn item that calls (public) methods on `Point` from the same impl which changed +mod fn_calls_methods_in_same_impl { + use point::Point; + + // FIXME(#37333) -- we should not need to typeck this again + #[rustc_dirty(label="TypeckItemBody", cfg="rpass2")] + pub fn check() { + let x = Point { x: 2.0, y: 2.0 }; + x.distance_from_origin(); + } +} + +/// A fn item that calls (public) methods on `Point` from another impl +mod fn_calls_methods_in_another_impl { + use point::Point; + + // FIXME(#37333) -- we should not need to typeck this again + #[rustc_dirty(label="TypeckItemBody", cfg="rpass2")] + pub fn check() { + let mut x = Point { x: 2.0, y: 2.0 }; + x.translate(3.0, 3.0); + } +} + +/// A fn item that makes an instance of `Point` but does not invoke methods +mod fn_make_struct { + use point::Point; + + // FIXME(#37333) -- we should not need to typeck this again + #[rustc_dirty(label="TypeckItemBody", cfg="rpass2")] + pub fn make_origin() -> Point { + Point { x: 2.0, y: 2.0 } + } +} + +/// A fn item that reads fields from `Point` but does not invoke methods +mod fn_read_field { + use point::Point; + + // FIXME(#37333) -- we should not need to typeck this again + #[rustc_dirty(label="TypeckItemBody", cfg="rpass2")] + pub fn get_x(p: Point) -> f32 { + p.x + } +} + +/// A fn item that writes to a field of `Point` but does not invoke methods +mod fn_write_field { + use point::Point; + + // FIXME(#37333) -- we should not need to typeck this again + #[rustc_dirty(label="TypeckItemBody", cfg="rpass2")] + pub fn inc_x(p: &mut Point) { + p.x += 1.0; + } +} + +fn main() { +} diff --git a/src/test/incremental/hashes/consts.rs b/src/test/incremental/hashes/consts.rs new file mode 100644 index 0000000000..10c02d84b3 --- /dev/null +++ b/src/test/incremental/hashes/consts.rs @@ -0,0 +1,132 @@ +// Copyright 2016 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + + +// This test case tests the incremental compilation hash (ICH) implementation +// for consts. + +// The general pattern followed here is: Change one thing between rev1 and rev2 +// and make sure that the hash has changed, then change nothing between rev2 and +// rev3 and make sure that the hash has not changed. + +// must-compile-successfully +// revisions: cfail1 cfail2 cfail3 +// compile-flags: -Z query-dep-graph + +#![allow(warnings)] +#![feature(rustc_attrs)] +#![crate_type="rlib"] + + +// Change const visibility --------------------------------------------------- +#[cfg(cfail1)] +const CONST_VISIBILITY: u8 = 0; + +#[cfg(not(cfail1))] +#[rustc_dirty(label="Hir", cfg="cfail2")] +#[rustc_clean(label="Hir", cfg="cfail3")] +#[rustc_metadata_dirty(cfg="cfail2")] +#[rustc_metadata_clean(cfg="cfail3")] +pub const CONST_VISIBILITY: u8 = 0; + + +// Change type from i32 to u32 ------------------------------------------------ +#[cfg(cfail1)] +const CONST_CHANGE_TYPE_1: i32 = 0; + +#[cfg(not(cfail1))] +#[rustc_dirty(label="Hir", cfg="cfail2")] +#[rustc_clean(label="Hir", cfg="cfail3")] +#[rustc_metadata_dirty(cfg="cfail2")] +#[rustc_metadata_clean(cfg="cfail3")] +const CONST_CHANGE_TYPE_1: u32 = 0; + + +// Change type from Option to Option -------------------------------- +#[cfg(cfail1)] +const CONST_CHANGE_TYPE_2: Option = None; + +#[cfg(not(cfail1))] +#[rustc_dirty(label="Hir", cfg="cfail2")] +#[rustc_clean(label="Hir", cfg="cfail3")] +#[rustc_metadata_dirty(cfg="cfail2")] +#[rustc_metadata_clean(cfg="cfail3")] +const CONST_CHANGE_TYPE_2: Option = None; + + +// Change value between simple literals --------------------------------------- +#[cfg(cfail1)] +const CONST_CHANGE_VALUE_1: i16 = 1; + +#[cfg(not(cfail1))] +#[rustc_dirty(label="Hir", cfg="cfail2")] +#[rustc_clean(label="Hir", cfg="cfail3")] +#[rustc_metadata_dirty(cfg="cfail2")] +#[rustc_metadata_clean(cfg="cfail3")] +const CONST_CHANGE_VALUE_1: i16 = 2; + + +// Change value between expressions ------------------------------------------- +#[cfg(cfail1)] +const CONST_CHANGE_VALUE_2: i16 = 1 + 1; + +#[cfg(not(cfail1))] +#[rustc_dirty(label="Hir", cfg="cfail2")] +#[rustc_clean(label="Hir", cfg="cfail3")] +#[rustc_metadata_dirty(cfg="cfail2")] +#[rustc_metadata_clean(cfg="cfail3")] +const CONST_CHANGE_VALUE_2: i16 = 1 + 2; + + +#[cfg(cfail1)] +const CONST_CHANGE_VALUE_3: i16 = 2 + 3; + +#[cfg(not(cfail1))] +#[rustc_dirty(label="Hir", cfg="cfail2")] +#[rustc_clean(label="Hir", cfg="cfail3")] +#[rustc_metadata_dirty(cfg="cfail2")] +#[rustc_metadata_clean(cfg="cfail3")] +const CONST_CHANGE_VALUE_3: i16 = 2 * 3; + + +#[cfg(cfail1)] +const CONST_CHANGE_VALUE_4: i16 = 1 + 2 * 3; + +#[cfg(not(cfail1))] +#[rustc_dirty(label="Hir", cfg="cfail2")] +#[rustc_clean(label="Hir", cfg="cfail3")] +#[rustc_metadata_dirty(cfg="cfail2")] +#[rustc_metadata_clean(cfg="cfail3")] +const CONST_CHANGE_VALUE_4: i16 = 1 + 2 * 4; + + +// Change type indirectly ----------------------------------------------------- +struct ReferencedType1; +struct ReferencedType2; + +mod const_change_type_indirectly { + #[cfg(cfail1)] + use super::ReferencedType1 as Type; + + #[cfg(not(cfail1))] + use super::ReferencedType2 as Type; + + #[rustc_dirty(label="Hir", cfg="cfail2")] + #[rustc_clean(label="Hir", cfg="cfail3")] + #[rustc_metadata_dirty(cfg="cfail2")] + #[rustc_metadata_clean(cfg="cfail3")] + const CONST_CHANGE_TYPE_INDIRECTLY_1: Type = Type; + + #[rustc_dirty(label="Hir", cfg="cfail2")] + #[rustc_clean(label="Hir", cfg="cfail3")] + #[rustc_metadata_dirty(cfg="cfail2")] + #[rustc_metadata_clean(cfg="cfail3")] + const CONST_CHANGE_TYPE_INDIRECTLY_2: Option = None; +} diff --git a/src/test/incremental/hashes/enum_defs.rs b/src/test/incremental/hashes/enum_defs.rs new file mode 100644 index 0000000000..aa17a24be2 --- /dev/null +++ b/src/test/incremental/hashes/enum_defs.rs @@ -0,0 +1,715 @@ +// Copyright 2016 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + + +// This test case tests the incremental compilation hash (ICH) implementation +// for enum definitions. + +// The general pattern followed here is: Change one thing between rev1 and rev2 +// and make sure that the hash has changed, then change nothing between rev2 and +// rev3 and make sure that the hash has not changed. + +// We also test the ICH for enum definitions exported in metadata. Same as +// above, we want to make sure that the change between rev1 and rev2 also +// results in a change of the ICH for the enum's metadata, and that it stays +// the same between rev2 and rev3. + +// must-compile-successfully +// revisions: cfail1 cfail2 cfail3 +// compile-flags: -Z query-dep-graph + +#![allow(warnings)] +#![feature(rustc_attrs)] +#![crate_type="rlib"] + + + +// Change enum visibility ----------------------------------------------------- +#[cfg(cfail1)] +enum EnumVisibility { A } + +#[cfg(not(cfail1))] +#[rustc_dirty(label="Hir", cfg="cfail2")] +#[rustc_clean(label="Hir", cfg="cfail3")] +#[rustc_metadata_clean(cfg="cfail3")] +pub enum EnumVisibility { A } + + + +// Change name of a c-style variant ------------------------------------------- +#[cfg(cfail1)] +enum EnumChangeNameCStyleVariant { + Variant1, + Variant2, +} + +#[cfg(not(cfail1))] +#[rustc_dirty(label="Hir", cfg="cfail2")] +#[rustc_clean(label="Hir", cfg="cfail3")] +#[rustc_metadata_dirty(cfg="cfail2")] +#[rustc_metadata_clean(cfg="cfail3")] +enum EnumChangeNameCStyleVariant { + Variant1, + Variant2Changed, +} + + + +// Change name of a tuple-style variant --------------------------------------- +#[cfg(cfail1)] +enum EnumChangeNameTupleStyleVariant { + Variant1, + Variant2(u32, f32), +} + +#[cfg(not(cfail1))] +#[rustc_dirty(label="Hir", cfg="cfail2")] +#[rustc_clean(label="Hir", cfg="cfail3")] +#[rustc_metadata_dirty(cfg="cfail2")] +#[rustc_metadata_clean(cfg="cfail3")] +enum EnumChangeNameTupleStyleVariant { + Variant1, + Variant2Changed(u32, f32), +} + + + +// Change name of a struct-style variant -------------------------------------- +#[cfg(cfail1)] +enum EnumChangeNameStructStyleVariant { + Variant1, + Variant2 { a: u32, b: f32 }, +} + +#[cfg(not(cfail1))] +#[rustc_dirty(label="Hir", cfg="cfail2")] +#[rustc_clean(label="Hir", cfg="cfail3")] +#[rustc_metadata_dirty(cfg="cfail2")] +#[rustc_metadata_clean(cfg="cfail3")] +enum EnumChangeNameStructStyleVariant { + Variant1, + Variant2Changed { a: u32, b: f32 }, +} + + + +// Change the value of a c-style variant -------------------------------------- +#[cfg(cfail1)] +enum EnumChangeValueCStyleVariant0 { + Variant1, + Variant2 = 11, +} + +#[cfg(not(cfail1))] +#[rustc_dirty(label="Hir", cfg="cfail2")] +#[rustc_clean(label="Hir", cfg="cfail3")] +#[rustc_metadata_dirty(cfg="cfail2")] +#[rustc_metadata_clean(cfg="cfail3")] +enum EnumChangeValueCStyleVariant0 { + Variant1, + Variant2 = 22, +} + +#[cfg(cfail1)] +enum EnumChangeValueCStyleVariant1 { + Variant1, + Variant2, +} + +#[cfg(not(cfail1))] +#[rustc_dirty(label="Hir", cfg="cfail2")] +#[rustc_clean(label="Hir", cfg="cfail3")] +#[rustc_metadata_dirty(cfg="cfail2")] +#[rustc_metadata_clean(cfg="cfail3")] +enum EnumChangeValueCStyleVariant1 { + Variant1, + Variant2 = 11, +} + + + +// Add a c-style variant ------------------------------------------------------ +#[cfg(cfail1)] +enum EnumAddCStyleVariant { + Variant1, +} + +#[cfg(not(cfail1))] +#[rustc_dirty(label="Hir", cfg="cfail2")] +#[rustc_clean(label="Hir", cfg="cfail3")] +#[rustc_metadata_dirty(cfg="cfail2")] +#[rustc_metadata_clean(cfg="cfail3")] +enum EnumAddCStyleVariant { + Variant1, + Variant2, +} + + + +// Remove a c-style variant --------------------------------------------------- +#[cfg(cfail1)] +enum EnumRemoveCStyleVariant { + Variant1, + Variant2, +} + +#[cfg(not(cfail1))] +#[rustc_dirty(label="Hir", cfg="cfail2")] +#[rustc_clean(label="Hir", cfg="cfail3")] +#[rustc_metadata_dirty(cfg="cfail2")] +#[rustc_metadata_clean(cfg="cfail3")] +enum EnumRemoveCStyleVariant { + Variant1, +} + + + +// Add a tuple-style variant -------------------------------------------------- +#[cfg(cfail1)] +enum EnumAddTupleStyleVariant { + Variant1, +} + +#[cfg(not(cfail1))] +#[rustc_dirty(label="Hir", cfg="cfail2")] +#[rustc_clean(label="Hir", cfg="cfail3")] +#[rustc_metadata_dirty(cfg="cfail2")] +#[rustc_metadata_clean(cfg="cfail3")] +enum EnumAddTupleStyleVariant { + Variant1, + Variant2(u32, f32), +} + + + +// Remove a tuple-style variant ----------------------------------------------- +#[cfg(cfail1)] +enum EnumRemoveTupleStyleVariant { + Variant1, + Variant2(u32, f32), +} + +#[cfg(not(cfail1))] +#[rustc_dirty(label="Hir", cfg="cfail2")] +#[rustc_clean(label="Hir", cfg="cfail3")] +#[rustc_metadata_dirty(cfg="cfail2")] +#[rustc_metadata_clean(cfg="cfail3")] +enum EnumRemoveTupleStyleVariant { + Variant1, +} + + + +// Add a struct-style variant ------------------------------------------------- +#[cfg(cfail1)] +enum EnumAddStructStyleVariant { + Variant1, +} + +#[cfg(not(cfail1))] +#[rustc_dirty(label="Hir", cfg="cfail2")] +#[rustc_clean(label="Hir", cfg="cfail3")] +#[rustc_metadata_dirty(cfg="cfail2")] +#[rustc_metadata_clean(cfg="cfail3")] +enum EnumAddStructStyleVariant { + Variant1, + Variant2 { a: u32, b: f32 }, +} + + + +// Remove a struct-style variant ---------------------------------------------- +#[cfg(cfail1)] +enum EnumRemoveStructStyleVariant { + Variant1, + Variant2 { a: u32, b: f32 }, +} + +#[cfg(not(cfail1))] +#[rustc_dirty(label="Hir", cfg="cfail2")] +#[rustc_clean(label="Hir", cfg="cfail3")] +#[rustc_metadata_dirty(cfg="cfail2")] +#[rustc_metadata_clean(cfg="cfail3")] +enum EnumRemoveStructStyleVariant { + Variant1, +} + + + +// Change the type of a field in a tuple-style variant ------------------------ +#[cfg(cfail1)] +enum EnumChangeFieldTypeTupleStyleVariant { + Variant1(u32, u32), +} + +#[cfg(not(cfail1))] +#[rustc_dirty(label="Hir", cfg="cfail2")] +#[rustc_clean(label="Hir", cfg="cfail3")] +#[rustc_metadata_dirty(cfg="cfail2")] +#[rustc_metadata_clean(cfg="cfail3")] +enum EnumChangeFieldTypeTupleStyleVariant { + Variant1(u32, u64), +} + + + +// Change the type of a field in a struct-style variant ----------------------- +#[cfg(cfail1)] +enum EnumChangeFieldTypeStructStyleVariant { + Variant1, + Variant2 { a: u32, b: u32 }, +} + +#[cfg(not(cfail1))] +#[rustc_dirty(label="Hir", cfg="cfail2")] +#[rustc_clean(label="Hir", cfg="cfail3")] +#[rustc_metadata_dirty(cfg="cfail2")] +#[rustc_metadata_clean(cfg="cfail3")] +enum EnumChangeFieldTypeStructStyleVariant { + Variant1, + Variant2 { a: u32, b: u64 }, +} + + + +// Change the name of a field in a struct-style variant ----------------------- +#[cfg(cfail1)] +enum EnumChangeFieldNameStructStyleVariant { + Variant1 { a: u32, b: u32 }, +} + +#[cfg(not(cfail1))] +#[rustc_dirty(label="Hir", cfg="cfail2")] +#[rustc_clean(label="Hir", cfg="cfail3")] +#[rustc_metadata_dirty(cfg="cfail2")] +#[rustc_metadata_clean(cfg="cfail3")] +enum EnumChangeFieldNameStructStyleVariant { + Variant1 { a: u32, c: u32 }, +} + + + +// Change order of fields in a tuple-style variant ---------------------------- +#[cfg(cfail1)] +enum EnumChangeOrderTupleStyleVariant { + Variant1(u32, u64), +} + +#[cfg(not(cfail1))] +#[rustc_dirty(label="Hir", cfg="cfail2")] +#[rustc_clean(label="Hir", cfg="cfail3")] +#[rustc_metadata_dirty(cfg="cfail2")] +#[rustc_metadata_clean(cfg="cfail3")] +enum EnumChangeOrderTupleStyleVariant { + Variant1(u64, u32), +} + + + +// Change order of fields in a struct-style variant --------------------------- +#[cfg(cfail1)] +enum EnumChangeFieldOrderStructStyleVariant { + Variant1 { a: u32, b: f32 }, +} + +#[cfg(not(cfail1))] +#[rustc_dirty(label="Hir", cfg="cfail2")] +#[rustc_clean(label="Hir", cfg="cfail3")] +#[rustc_metadata_dirty(cfg="cfail2")] +#[rustc_metadata_clean(cfg="cfail3")] +enum EnumChangeFieldOrderStructStyleVariant { + Variant1 { b: f32, a: u32 }, +} + + + +// Add a field to a tuple-style variant --------------------------------------- +#[cfg(cfail1)] +enum EnumAddFieldTupleStyleVariant { + Variant1(u32, u32), +} + +#[cfg(not(cfail1))] +#[rustc_dirty(label="Hir", cfg="cfail2")] +#[rustc_clean(label="Hir", cfg="cfail3")] +#[rustc_metadata_dirty(cfg="cfail2")] +#[rustc_metadata_clean(cfg="cfail3")] +enum EnumAddFieldTupleStyleVariant { + Variant1(u32, u32, u32), +} + + + +// Add a field to a struct-style variant -------------------------------------- +#[cfg(cfail1)] +enum EnumAddFieldStructStyleVariant { + Variant1 { a: u32, b: u32 }, +} + +#[cfg(not(cfail1))] +#[rustc_dirty(label="Hir", cfg="cfail2")] +#[rustc_clean(label="Hir", cfg="cfail3")] +#[rustc_metadata_dirty(cfg="cfail2")] +#[rustc_metadata_clean(cfg="cfail3")] +enum EnumAddFieldStructStyleVariant { + Variant1 { a: u32, b: u32, c: u32 }, +} + + + +// Add #[must_use] to the enum ------------------------------------------------ +#[cfg(cfail1)] +enum EnumAddMustUse { + Variant1, + Variant2, +} + +#[cfg(not(cfail1))] +#[rustc_dirty(label="Hir", cfg="cfail2")] +#[rustc_clean(label="Hir", cfg="cfail3")] +#[rustc_metadata_dirty(cfg="cfail2")] +#[rustc_metadata_clean(cfg="cfail3")] +#[must_use] +enum EnumAddMustUse { + Variant1, + Variant2, +} + + + +// Add #[repr(C)] to the enum ------------------------------------------------- +#[cfg(cfail1)] +enum EnumAddReprC { + Variant1, + Variant2, +} + +#[cfg(not(cfail1))] +#[rustc_dirty(label="Hir", cfg="cfail2")] +#[rustc_clean(label="Hir", cfg="cfail3")] +#[rustc_metadata_dirty(cfg="cfail2")] +#[rustc_metadata_clean(cfg="cfail3")] +#[repr(C)] +enum EnumAddReprC { + Variant1, + Variant2, +} + + + +// Change the name of a type parameter ---------------------------------------- +#[cfg(cfail1)] +enum EnumChangeNameOfTypeParameter { + Variant1(S), +} + +#[cfg(not(cfail1))] +#[rustc_dirty(label="Hir", cfg="cfail2")] +#[rustc_clean(label="Hir", cfg="cfail3")] +#[rustc_metadata_dirty(cfg="cfail2")] +#[rustc_metadata_clean(cfg="cfail3")] +#[repr(C)] +enum EnumChangeNameOfTypeParameter { + Variant1(T), +} + + + +// Add a type parameter ------------------------------------------------------ +#[cfg(cfail1)] +enum EnumAddTypeParameter { + Variant1(S), + Variant2(S), +} + +#[cfg(not(cfail1))] +#[rustc_dirty(label="Hir", cfg="cfail2")] +#[rustc_clean(label="Hir", cfg="cfail3")] +#[rustc_metadata_dirty(cfg="cfail2")] +#[rustc_metadata_clean(cfg="cfail3")] +#[repr(C)] +enum EnumAddTypeParameter { + Variant1(S), + Variant2(T), +} + + + +// Change the name of a lifetime parameter ------------------------------------ +#[cfg(cfail1)] +enum EnumChangeNameOfLifetimeParameter<'a> { + Variant1(&'a u32), +} + +#[cfg(not(cfail1))] +#[rustc_dirty(label="Hir", cfg="cfail2")] +#[rustc_clean(label="Hir", cfg="cfail3")] +#[rustc_metadata_dirty(cfg="cfail2")] +#[rustc_metadata_clean(cfg="cfail3")] +#[repr(C)] +enum EnumChangeNameOfLifetimeParameter<'b> { + Variant1(&'b u32), +} + + + +// Add a lifetime parameter --------------------------------------------------- +#[cfg(cfail1)] +enum EnumAddLifetimeParameter<'a> { + Variant1(&'a u32), + Variant2(&'a u32), +} + +#[cfg(not(cfail1))] +#[rustc_dirty(label="Hir", cfg="cfail2")] +#[rustc_clean(label="Hir", cfg="cfail3")] +#[rustc_metadata_dirty(cfg="cfail2")] +#[rustc_metadata_clean(cfg="cfail3")] +#[repr(C)] +enum EnumAddLifetimeParameter<'a, 'b> { + Variant1(&'a u32), + Variant2(&'b u32), +} + + + +// Add a lifetime bound to a lifetime parameter ------------------------------- +#[cfg(cfail1)] +enum EnumAddLifetimeParameterBound<'a, 'b> { + Variant1(&'a u32), + Variant2(&'b u32), +} + +#[cfg(not(cfail1))] +#[rustc_dirty(label="Hir", cfg="cfail2")] +#[rustc_clean(label="Hir", cfg="cfail3")] +#[rustc_metadata_dirty(cfg="cfail2")] +#[rustc_metadata_clean(cfg="cfail3")] +#[repr(C)] +enum EnumAddLifetimeParameterBound<'a, 'b: 'a> { + Variant1(&'a u32), + Variant2(&'b u32), +} + +// Add a lifetime bound to a type parameter ----------------------------------- +#[cfg(cfail1)] +enum EnumAddLifetimeBoundToParameter<'a, T> { + Variant1(T), + Variant2(&'a u32), +} + +#[cfg(not(cfail1))] +#[rustc_dirty(label="Hir", cfg="cfail2")] +#[rustc_clean(label="Hir", cfg="cfail3")] +#[rustc_metadata_dirty(cfg="cfail2")] +#[rustc_metadata_clean(cfg="cfail3")] +#[repr(C)] +enum EnumAddLifetimeBoundToParameter<'a, T: 'a> { + Variant1(T), + Variant2(&'a u32), +} + + + +// Add a trait bound to a type parameter -------------------------------------- +#[cfg(cfail1)] +enum EnumAddTraitBound { + Variant1(S), +} + +#[cfg(not(cfail1))] +#[rustc_dirty(label="Hir", cfg="cfail2")] +#[rustc_clean(label="Hir", cfg="cfail3")] +#[rustc_metadata_dirty(cfg="cfail2")] +#[rustc_metadata_clean(cfg="cfail3")] +#[repr(C)] +enum EnumAddTraitBound { + Variant1(T), +} + + + +// Add a lifetime bound to a lifetime parameter in where clause --------------- +#[cfg(cfail1)] +enum EnumAddLifetimeParameterBoundWhere<'a, 'b> { + Variant1(&'a u32), + Variant2(&'b u32), +} + +#[cfg(not(cfail1))] +#[rustc_dirty(label="Hir", cfg="cfail2")] +#[rustc_clean(label="Hir", cfg="cfail3")] +#[rustc_metadata_dirty(cfg="cfail2")] +#[rustc_metadata_clean(cfg="cfail3")] +#[repr(C)] +enum EnumAddLifetimeParameterBoundWhere<'a, 'b> where 'b: 'a { + Variant1(&'a u32), + Variant2(&'b u32), +} + + + +// Add a lifetime bound to a type parameter in where clause ------------------- +#[cfg(cfail1)] +enum EnumAddLifetimeBoundToParameterWhere<'a, T> { + Variant1(T), + Variant2(&'a u32), +} + +#[cfg(not(cfail1))] +#[rustc_dirty(label="Hir", cfg="cfail2")] +#[rustc_clean(label="Hir", cfg="cfail3")] +#[rustc_metadata_dirty(cfg="cfail2")] +#[rustc_metadata_clean(cfg="cfail3")] +#[repr(C)] +enum EnumAddLifetimeBoundToParameterWhere<'a, T> where T: 'a { + Variant1(T), + Variant2(&'a u32), +} + + + +// Add a trait bound to a type parameter in where clause ---------------------- +#[cfg(cfail1)] +enum EnumAddTraitBoundWhere { + Variant1(S), +} + +#[cfg(not(cfail1))] +#[rustc_dirty(label="Hir", cfg="cfail2")] +#[rustc_clean(label="Hir", cfg="cfail3")] +#[rustc_metadata_dirty(cfg="cfail2")] +#[rustc_metadata_clean(cfg="cfail3")] +#[repr(C)] +enum EnumAddTraitBoundWhere where T: Sync { + Variant1(T), +} + + + +// In an enum with two variants, swap usage of type parameters ---------------- +#[cfg(cfail1)] +enum EnumSwapUsageTypeParameters { + Variant1 { a: A }, + Variant2 { a: B }, +} + +#[cfg(not(cfail1))] +#[rustc_dirty(label="Hir", cfg="cfail2")] +#[rustc_clean(label="Hir", cfg="cfail3")] +#[rustc_metadata_dirty(cfg="cfail2")] +#[rustc_metadata_clean(cfg="cfail3")] +enum EnumSwapUsageTypeParameters { + Variant1 { a: B }, + Variant2 { a: A }, +} + + + +// In an enum with two variants, swap usage of lifetime parameters ------------ +#[cfg(cfail1)] +enum EnumSwapUsageLifetimeParameters<'a, 'b> { + Variant1 { a: &'a u32 }, + Variant2 { b: &'b u32 }, +} + +#[cfg(not(cfail1))] +#[rustc_dirty(label="Hir", cfg="cfail2")] +#[rustc_clean(label="Hir", cfg="cfail3")] +#[rustc_metadata_dirty(cfg="cfail2")] +#[rustc_metadata_clean(cfg="cfail3")] +enum EnumSwapUsageLifetimeParameters<'a, 'b> { + Variant1 { a: &'b u32 }, + Variant2 { b: &'a u32 }, +} + + + +struct ReferencedType1; +struct ReferencedType2; + + + +// Change field type in tuple-style variant indirectly by modifying a use statement +mod change_field_type_indirectly_tuple_style { + #[cfg(cfail1)] + use super::ReferencedType1 as FieldType; + #[cfg(not(cfail1))] + use super::ReferencedType2 as FieldType; + + #[rustc_dirty(label="Hir", cfg="cfail2")] + #[rustc_clean(label="Hir", cfg="cfail3")] + #[rustc_metadata_dirty(cfg="cfail2")] + #[rustc_metadata_clean(cfg="cfail3")] + enum TupleStyle { + Variant1(FieldType) + } +} + + + +// Change field type in record-style variant indirectly by modifying a use statement +mod change_field_type_indirectly_struct_style { + #[cfg(cfail1)] + use super::ReferencedType1 as FieldType; + #[cfg(not(cfail1))] + use super::ReferencedType2 as FieldType; + + #[rustc_dirty(label="Hir", cfg="cfail2")] + #[rustc_clean(label="Hir", cfg="cfail3")] + #[rustc_metadata_dirty(cfg="cfail2")] + #[rustc_metadata_clean(cfg="cfail3")] + enum StructStyle { + Variant1 { a: FieldType } + } +} + + + +trait ReferencedTrait1 {} +trait ReferencedTrait2 {} + + + +// Change trait bound of type parameter indirectly by modifying a use statement +mod change_trait_bound_indirectly { + #[cfg(cfail1)] + use super::ReferencedTrait1 as Trait; + #[cfg(not(cfail1))] + use super::ReferencedTrait2 as Trait; + + #[rustc_dirty(label="Hir", cfg="cfail2")] + #[rustc_clean(label="Hir", cfg="cfail3")] + #[rustc_metadata_dirty(cfg="cfail2")] + #[rustc_metadata_clean(cfg="cfail3")] + enum Enum { + Variant1(T) + } +} + + + +// Change trait bound of type parameter in where clause indirectly by modifying a use statement +mod change_trait_bound_indirectly_where { + #[cfg(cfail1)] + use super::ReferencedTrait1 as Trait; + #[cfg(not(cfail1))] + use super::ReferencedTrait2 as Trait; + + #[rustc_dirty(label="Hir", cfg="cfail2")] + #[rustc_clean(label="Hir", cfg="cfail3")] + #[rustc_metadata_dirty(cfg="cfail2")] + #[rustc_metadata_clean(cfg="cfail3")] + enum Enum where T: Trait { + Variant1(T) + } +} + + diff --git a/src/test/incremental/hashes/function_interfaces.rs b/src/test/incremental/hashes/function_interfaces.rs new file mode 100644 index 0000000000..93d94cd1a1 --- /dev/null +++ b/src/test/incremental/hashes/function_interfaces.rs @@ -0,0 +1,400 @@ +// Copyright 2016 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + + +// This test case tests the incremental compilation hash (ICH) implementation +// for function interfaces. + +// The general pattern followed here is: Change one thing between rev1 and rev2 +// and make sure that the hash has changed, then change nothing between rev2 and +// rev3 and make sure that the hash has not changed. + +// must-compile-successfully +// revisions: cfail1 cfail2 cfail3 +// compile-flags: -Z query-dep-graph + + +#![allow(warnings)] +#![feature(conservative_impl_trait)] +#![feature(intrinsics)] +#![feature(linkage)] +#![feature(rustc_attrs)] +#![crate_type="rlib"] + + +// Add Parameter --------------------------------------------------------------- + +#[cfg(cfail1)] +fn add_parameter() {} + +#[cfg(not(cfail1))] +#[rustc_dirty(label="Hir", cfg="cfail2")] +#[rustc_clean(label="Hir", cfg="cfail3")] +#[rustc_metadata_dirty(cfg="cfail2")] +#[rustc_metadata_clean(cfg="cfail3")] +fn add_parameter(p: i32) {} + + +// Add Return Type ------------------------------------------------------------- + +#[cfg(cfail1)] +fn add_return_type() {} + +#[cfg(not(cfail1))] +#[rustc_dirty(label="Hir", cfg="cfail2")] +#[rustc_clean(label="Hir", cfg="cfail3")] +#[rustc_metadata_dirty(cfg="cfail2")] +#[rustc_metadata_clean(cfg="cfail3")] +fn add_return_type() -> () {} + + +// Change Parameter Type ------------------------------------------------------- + +#[cfg(cfail1)] +fn type_of_parameter(p: i32) {} + +#[cfg(not(cfail1))] +#[rustc_dirty(label="Hir", cfg="cfail2")] +#[rustc_clean(label="Hir", cfg="cfail3")] +#[rustc_metadata_dirty(cfg="cfail2")] +#[rustc_metadata_clean(cfg="cfail3")] +fn type_of_parameter(p: i64) {} + + +// Change Parameter Type Reference --------------------------------------------- + +#[cfg(cfail1)] +fn type_of_parameter_ref(p: &i32) {} + +#[cfg(not(cfail1))] +#[rustc_dirty(label="Hir", cfg="cfail2")] +#[rustc_clean(label="Hir", cfg="cfail3")] +#[rustc_metadata_dirty(cfg="cfail2")] +#[rustc_metadata_clean(cfg="cfail3")] +fn type_of_parameter_ref(p: &mut i32) {} + + +// Change Parameter Order ------------------------------------------------------ + +#[cfg(cfail1)] +fn order_of_parameters(p1: i32, p2: i64) {} + +#[cfg(not(cfail1))] +#[rustc_dirty(label="Hir", cfg="cfail2")] +#[rustc_clean(label="Hir", cfg="cfail3")] +#[rustc_metadata_dirty(cfg="cfail2")] +#[rustc_metadata_clean(cfg="cfail3")] +fn order_of_parameters(p2: i64, p1: i32) {} + + +// Unsafe ---------------------------------------------------------------------- + +#[cfg(cfail1)] +fn make_unsafe() {} + +#[cfg(not(cfail1))] +#[rustc_dirty(label="Hir", cfg="cfail2")] +#[rustc_clean(label="Hir", cfg="cfail3")] +#[rustc_metadata_dirty(cfg="cfail2")] +#[rustc_metadata_clean(cfg="cfail3")] +unsafe fn make_unsafe() {} + + +// Extern ---------------------------------------------------------------------- + +#[cfg(cfail1)] +fn make_extern() {} + +#[cfg(not(cfail1))] +#[rustc_dirty(label="Hir", cfg="cfail2")] +#[rustc_clean(label="Hir", cfg="cfail3")] +#[rustc_metadata_dirty(cfg="cfail2")] +#[rustc_metadata_clean(cfg="cfail3")] +extern fn make_extern() {} + + +// Extern C Extern Rust-Intrinsic ---------------------------------------------- + +#[cfg(cfail1)] +extern "C" fn make_intrinsic() {} + +#[cfg(not(cfail1))] +#[rustc_dirty(label="Hir", cfg="cfail2")] +#[rustc_clean(label="Hir", cfg="cfail3")] +#[rustc_metadata_dirty(cfg="cfail2")] +#[rustc_metadata_clean(cfg="cfail3")] +extern "rust-intrinsic" fn make_intrinsic() {} + + +// Type Parameter -------------------------------------------------------------- + +#[cfg(cfail1)] +fn type_parameter() {} + +#[cfg(not(cfail1))] +#[rustc_dirty(label="Hir", cfg="cfail2")] +#[rustc_clean(label="Hir", cfg="cfail3")] +#[rustc_metadata_dirty(cfg="cfail2")] +#[rustc_metadata_clean(cfg="cfail3")] +fn type_parameter() {} + + +// Lifetime Parameter ---------------------------------------------------------- + +#[cfg(cfail1)] +fn lifetime_parameter() {} + +#[cfg(not(cfail1))] +#[rustc_dirty(label="Hir", cfg="cfail2")] +#[rustc_clean(label="Hir", cfg="cfail3")] +#[rustc_metadata_dirty(cfg="cfail2")] +#[rustc_metadata_clean(cfg="cfail3")] +fn lifetime_parameter<'a>() {} + + +// Trait Bound ----------------------------------------------------------------- + +#[cfg(cfail1)] +fn trait_bound() {} + +#[cfg(not(cfail1))] +#[rustc_dirty(label="Hir", cfg="cfail2")] +#[rustc_clean(label="Hir", cfg="cfail3")] +#[rustc_metadata_dirty(cfg="cfail2")] +#[rustc_metadata_clean(cfg="cfail3")] +fn trait_bound() {} + + +// Builtin Bound --------------------------------------------------------------- + +#[cfg(cfail1)] +fn builtin_bound() {} + +#[cfg(not(cfail1))] +#[rustc_dirty(label="Hir", cfg="cfail2")] +#[rustc_clean(label="Hir", cfg="cfail3")] +#[rustc_metadata_dirty(cfg="cfail2")] +#[rustc_metadata_clean(cfg="cfail3")] +fn builtin_bound() {} + + +// Lifetime Bound -------------------------------------------------------------- + +#[cfg(cfail1)] +fn lifetime_bound<'a, T>() {} + +#[cfg(not(cfail1))] +#[rustc_dirty(label="Hir", cfg="cfail2")] +#[rustc_clean(label="Hir", cfg="cfail3")] +#[rustc_metadata_dirty(cfg="cfail2")] +#[rustc_metadata_clean(cfg="cfail3")] +fn lifetime_bound<'a, T: 'a>() {} + + +// Second Trait Bound ---------------------------------------------------------- + +#[cfg(cfail1)] +fn second_trait_bound() {} + +#[cfg(not(cfail1))] +#[rustc_dirty(label="Hir", cfg="cfail2")] +#[rustc_clean(label="Hir", cfg="cfail3")] +#[rustc_metadata_dirty(cfg="cfail2")] +#[rustc_metadata_clean(cfg="cfail3")] +fn second_trait_bound() {} + + +// Second Builtin Bound -------------------------------------------------------- + +#[cfg(cfail1)] +fn second_builtin_bound() {} + +#[cfg(not(cfail1))] +#[rustc_dirty(label="Hir", cfg="cfail2")] +#[rustc_clean(label="Hir", cfg="cfail3")] +#[rustc_metadata_dirty(cfg="cfail2")] +#[rustc_metadata_clean(cfg="cfail3")] +fn second_builtin_bound() {} + + +// Second Lifetime Bound ------------------------------------------------------- + +#[cfg(cfail1)] +fn second_lifetime_bound<'a, 'b, T: 'a>() {} + +#[cfg(not(cfail1))] +#[rustc_dirty(label="Hir", cfg="cfail2")] +#[rustc_clean(label="Hir", cfg="cfail3")] +#[rustc_metadata_dirty(cfg="cfail2")] +#[rustc_metadata_clean(cfg="cfail3")] +fn second_lifetime_bound<'a, 'b, T: 'a + 'b>() {} + + +// Inline ---------------------------------------------------------------------- + +#[cfg(cfail1)] +fn inline() {} + +#[cfg(not(cfail1))] +#[rustc_dirty(label="Hir", cfg="cfail2")] +#[rustc_clean(label="Hir", cfg="cfail3")] +#[rustc_metadata_dirty(cfg="cfail2")] +#[rustc_metadata_clean(cfg="cfail3")] +#[inline] +fn inline() {} + + +// Inline Never ---------------------------------------------------------------- + +#[cfg(cfail1)] +#[inline(always)] +fn inline_never() {} + +#[cfg(not(cfail1))] +#[rustc_dirty(label="Hir", cfg="cfail2")] +#[rustc_clean(label="Hir", cfg="cfail3")] +#[rustc_metadata_dirty(cfg="cfail2")] +#[rustc_metadata_clean(cfg="cfail3")] +#[inline(never)] +fn inline_never() {} + + +// No Mangle ------------------------------------------------------------------- + +#[cfg(cfail1)] +fn no_mangle() {} + +#[cfg(not(cfail1))] +#[rustc_dirty(label="Hir", cfg="cfail2")] +#[rustc_clean(label="Hir", cfg="cfail3")] +#[rustc_metadata_dirty(cfg="cfail2")] +#[rustc_metadata_clean(cfg="cfail3")] +#[no_mangle] +fn no_mangle() {} + + +// Linkage --------------------------------------------------------------------- + +#[cfg(cfail1)] +fn linkage() {} + +#[cfg(not(cfail1))] +#[rustc_dirty(label="Hir", cfg="cfail2")] +#[rustc_clean(label="Hir", cfg="cfail3")] +#[rustc_metadata_dirty(cfg="cfail2")] +#[rustc_metadata_clean(cfg="cfail3")] +#[linkage="weak_odr"] +fn linkage() {} + + +// Return Impl Trait ----------------------------------------------------------- + +#[cfg(cfail1)] +fn return_impl_trait() -> i32 { + 0 +} + +#[cfg(not(cfail1))] +#[rustc_dirty(label="Hir", cfg="cfail2")] +#[rustc_clean(label="Hir", cfg="cfail3")] +#[rustc_metadata_dirty(cfg="cfail2")] +#[rustc_metadata_clean(cfg="cfail3")] +fn return_impl_trait() -> impl Clone { + 0 +} + + +// Change Return Impl Trait ---------------------------------------------------- + +#[cfg(cfail1)] +fn change_return_impl_trait() -> impl Clone { + 0 +} + +#[cfg(not(cfail1))] +#[rustc_dirty(label="Hir", cfg="cfail2")] +#[rustc_clean(label="Hir", cfg="cfail3")] +#[rustc_metadata_dirty(cfg="cfail2")] +#[rustc_metadata_clean(cfg="cfail3")] +fn change_return_impl_trait() -> impl Copy { + 0 +} + + +// Change Return Type Indirectly ----------------------------------------------- + +struct ReferencedType1; +struct ReferencedType2; + +mod change_return_type_indirectly { + #[cfg(cfail1)] + use super::ReferencedType1 as ReturnType; + #[cfg(not(cfail1))] + use super::ReferencedType2 as ReturnType; + + #[rustc_dirty(label="Hir", cfg="cfail2")] + #[rustc_clean(label="Hir", cfg="cfail3")] + #[rustc_metadata_dirty(cfg="cfail2")] + #[rustc_metadata_clean(cfg="cfail3")] + fn indirect_return_type() -> ReturnType { + ReturnType {} + } +} + + +// Change Parameter Type Indirectly -------------------------------------------- + +mod change_parameter_type_indirectly { + #[cfg(cfail1)] + use super::ReferencedType1 as ParameterType; + #[cfg(not(cfail1))] + use super::ReferencedType2 as ParameterType; + + #[rustc_dirty(label="Hir", cfg="cfail2")] + #[rustc_clean(label="Hir", cfg="cfail3")] + #[rustc_metadata_dirty(cfg="cfail2")] + #[rustc_metadata_clean(cfg="cfail3")] + fn indirect_parameter_type(p: ParameterType) {} +} + + +// Change Trait Bound Indirectly ----------------------------------------------- + +trait ReferencedTrait1 {} +trait ReferencedTrait2 {} + +mod change_trait_bound_indirectly { + #[cfg(cfail1)] + use super::ReferencedTrait1 as Trait; + #[cfg(not(cfail1))] + use super::ReferencedTrait2 as Trait; + + #[rustc_dirty(label="Hir", cfg="cfail2")] + #[rustc_clean(label="Hir", cfg="cfail3")] + #[rustc_metadata_dirty(cfg="cfail2")] + #[rustc_metadata_clean(cfg="cfail3")] + fn indirect_trait_bound(p: T) {} +} + + +// Change Trait Bound Indirectly In Where Clause ------------------------------- + +mod change_trait_bound_indirectly_in_where_clause { + #[cfg(cfail1)] + use super::ReferencedTrait1 as Trait; + #[cfg(not(cfail1))] + use super::ReferencedTrait2 as Trait; + + #[rustc_dirty(label="Hir", cfg="cfail2")] + #[rustc_clean(label="Hir", cfg="cfail3")] + #[rustc_metadata_dirty(cfg="cfail2")] + #[rustc_metadata_clean(cfg="cfail3")] + fn indirect_trait_bound_where(p: T) where T: Trait {} +} diff --git a/src/test/incremental/hashes/panic_exprs.rs b/src/test/incremental/hashes/panic_exprs.rs new file mode 100644 index 0000000000..f5f4c0042b --- /dev/null +++ b/src/test/incremental/hashes/panic_exprs.rs @@ -0,0 +1,173 @@ +// Copyright 2016 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +// This test case tests the incremental compilation hash (ICH) implementation +// for exprs that can panic at runtime (e.g. because of bounds checking). For +// these expressions an error message containing their source location is +// generated, so their hash must always depend on their location in the source +// code, not just when debuginfo is enabled. + +// The general pattern followed here is: Change one thing between rev1 and rev2 +// and make sure that the hash has changed, then change nothing between rev2 and +// rev3 and make sure that the hash has not changed. + +// must-compile-successfully +// revisions: cfail1 cfail2 cfail3 +// compile-flags: -Z query-dep-graph -C debug-assertions + +#![allow(warnings)] +#![feature(rustc_attrs)] +#![crate_type="rlib"] + + +// Indexing expression --------------------------------------------------------- +#[cfg(cfail1)] +pub fn indexing(slice: &[u8]) -> u8 { + slice[100] +} + +#[cfg(not(cfail1))] +#[rustc_dirty(label="Hir", cfg="cfail2")] +#[rustc_clean(label="Hir", cfg="cfail3")] +#[rustc_metadata_dirty(cfg="cfail2")] +#[rustc_metadata_clean(cfg="cfail3")] +pub fn indexing(slice: &[u8]) -> u8 { + slice[100] +} + + +// Arithmetic overflow plus ---------------------------------------------------- +#[cfg(cfail1)] +pub fn arithmetic_overflow_plus(val: i32) -> i32 { + val + 1 +} + +#[cfg(not(cfail1))] +#[rustc_dirty(label="Hir", cfg="cfail2")] +#[rustc_clean(label="Hir", cfg="cfail3")] +#[rustc_metadata_dirty(cfg="cfail2")] +#[rustc_metadata_clean(cfg="cfail3")] +pub fn arithmetic_overflow_plus(val: i32) -> i32 { + val + 1 +} + + +// Arithmetic overflow minus ---------------------------------------------------- +#[cfg(cfail1)] +pub fn arithmetic_overflow_minus(val: i32) -> i32 { + val - 1 +} + +#[cfg(not(cfail1))] +#[rustc_dirty(label="Hir", cfg="cfail2")] +#[rustc_clean(label="Hir", cfg="cfail3")] +#[rustc_metadata_dirty(cfg="cfail2")] +#[rustc_metadata_clean(cfg="cfail3")] +pub fn arithmetic_overflow_minus(val: i32) -> i32 { + val - 1 +} + + +// Arithmetic overflow mult ---------------------------------------------------- +#[cfg(cfail1)] +pub fn arithmetic_overflow_mult(val: i32) -> i32 { + val * 2 +} + +#[cfg(not(cfail1))] +#[rustc_dirty(label="Hir", cfg="cfail2")] +#[rustc_clean(label="Hir", cfg="cfail3")] +#[rustc_metadata_dirty(cfg="cfail2")] +#[rustc_metadata_clean(cfg="cfail3")] +pub fn arithmetic_overflow_mult(val: i32) -> i32 { + val * 2 +} + + +// Arithmetic overflow negation ------------------------------------------------ +#[cfg(cfail1)] +pub fn arithmetic_overflow_negation(val: i32) -> i32 { + -val +} + +#[cfg(not(cfail1))] +#[rustc_dirty(label="Hir", cfg="cfail2")] +#[rustc_clean(label="Hir", cfg="cfail3")] +#[rustc_metadata_dirty(cfg="cfail2")] +#[rustc_metadata_clean(cfg="cfail3")] +pub fn arithmetic_overflow_negation(val: i32) -> i32 { + -val +} + + +// Division by zero ------------------------------------------------------------ +#[cfg(cfail1)] +pub fn division_by_zero(val: i32) -> i32 { + 2 / val +} + +#[cfg(not(cfail1))] +#[rustc_dirty(label="Hir", cfg="cfail2")] +#[rustc_clean(label="Hir", cfg="cfail3")] +#[rustc_metadata_dirty(cfg="cfail2")] +#[rustc_metadata_clean(cfg="cfail3")] +pub fn division_by_zero(val: i32) -> i32 { + 2 / val +} + +// Division by zero ------------------------------------------------------------ +#[cfg(cfail1)] +pub fn mod_by_zero(val: i32) -> i32 { + 2 % val +} + +#[cfg(not(cfail1))] +#[rustc_dirty(label="Hir", cfg="cfail2")] +#[rustc_clean(label="Hir", cfg="cfail3")] +#[rustc_metadata_dirty(cfg="cfail2")] +#[rustc_metadata_clean(cfg="cfail3")] +pub fn mod_by_zero(val: i32) -> i32 { + 2 % val +} + + + +// THE FOLLOWING ITEMS SHOULD NOT BE INFLUENCED BY THEIR SOURCE LOCATION + +// bitwise --------------------------------------------------------------------- +#[cfg(cfail1)] +pub fn bitwise(val: i32) -> i32 { + !val & 0x101010101 | 0x45689 ^ 0x2372382 << 1 >> 1 +} + +#[cfg(not(cfail1))] +#[rustc_clean(label="Hir", cfg="cfail2")] +#[rustc_clean(label="Hir", cfg="cfail3")] +#[rustc_metadata_clean(cfg="cfail2")] +#[rustc_metadata_clean(cfg="cfail3")] +pub fn bitwise(val: i32) -> i32 { + !val & 0x101010101 | 0x45689 ^ 0x2372382 << 1 >> 1 +} + + +// logical --------------------------------------------------------------------- +#[cfg(cfail1)] +pub fn logical(val1: bool, val2: bool, val3: bool) -> bool { + val1 && val2 || val3 +} + +#[cfg(not(cfail1))] +#[rustc_clean(label="Hir", cfg="cfail2")] +#[rustc_clean(label="Hir", cfg="cfail3")] +#[rustc_metadata_clean(cfg="cfail2")] +#[rustc_metadata_clean(cfg="cfail3")] +pub fn logical(val1: bool, val2: bool, val3: bool) -> bool { + val1 && val2 || val3 +} diff --git a/src/test/incremental/hashes/panic_exprs_no_overflow_checks.rs b/src/test/incremental/hashes/panic_exprs_no_overflow_checks.rs new file mode 100644 index 0000000000..b84b7f5f37 --- /dev/null +++ b/src/test/incremental/hashes/panic_exprs_no_overflow_checks.rs @@ -0,0 +1,251 @@ +// Copyright 2016 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +// This test case tests the incremental compilation hash (ICH) implementation +// for exprs that can panic at runtime (e.g. because of bounds checking). For +// these expressions an error message containing their source location is +// generated, so their hash must always depend on their location in the source +// code, not just when debuginfo is enabled. + +// As opposed to the panic_exprs.rs test case, this test case checks that things +// behave as expected when overflow checks are off: +// +// - Addition, subtraction, and multiplication do not change the ICH, unless +// the function containing them is marked with rustc_inherit_overflow_checks. +// - Division by zero and bounds checks always influence the ICH + +// The general pattern followed here is: Change one thing between rev1 and rev2 +// and make sure that the hash has changed, then change nothing between rev2 and +// rev3 and make sure that the hash has not changed. + +// must-compile-successfully +// revisions: cfail1 cfail2 cfail3 +// compile-flags: -Z query-dep-graph -Z force-overflow-checks=off + +#![allow(warnings)] +#![feature(rustc_attrs)] +#![crate_type="rlib"] + + +// Indexing expression --------------------------------------------------------- +#[cfg(cfail1)] +pub fn indexing(slice: &[u8]) -> u8 { + slice[100] +} + +#[cfg(not(cfail1))] +#[rustc_dirty(label="Hir", cfg="cfail2")] +#[rustc_clean(label="Hir", cfg="cfail3")] +#[rustc_metadata_dirty(cfg="cfail2")] +#[rustc_metadata_clean(cfg="cfail3")] +pub fn indexing(slice: &[u8]) -> u8 { + slice[100] +} + + +// Arithmetic overflow plus ---------------------------------------------------- +#[cfg(cfail1)] +#[rustc_inherit_overflow_checks] +pub fn arithmetic_overflow_plus_inherit(val: i32) -> i32 { + val + 1 +} + +#[cfg(not(cfail1))] +#[rustc_dirty(label="Hir", cfg="cfail2")] +#[rustc_clean(label="Hir", cfg="cfail3")] +#[rustc_metadata_dirty(cfg="cfail2")] +#[rustc_metadata_clean(cfg="cfail3")] +#[rustc_inherit_overflow_checks] +pub fn arithmetic_overflow_plus_inherit(val: i32) -> i32 { + val + 1 +} + + +// Arithmetic overflow minus ---------------------------------------------------- +#[cfg(cfail1)] +#[rustc_inherit_overflow_checks] +pub fn arithmetic_overflow_minus_inherit(val: i32) -> i32 { + val - 1 +} + +#[cfg(not(cfail1))] +#[rustc_dirty(label="Hir", cfg="cfail2")] +#[rustc_clean(label="Hir", cfg="cfail3")] +#[rustc_metadata_dirty(cfg="cfail2")] +#[rustc_metadata_clean(cfg="cfail3")] +#[rustc_inherit_overflow_checks] +pub fn arithmetic_overflow_minus_inherit(val: i32) -> i32 { + val - 1 +} + + +// Arithmetic overflow mult ---------------------------------------------------- +#[cfg(cfail1)] +#[rustc_inherit_overflow_checks] +pub fn arithmetic_overflow_mult_inherit(val: i32) -> i32 { + val * 2 +} + +#[cfg(not(cfail1))] +#[rustc_dirty(label="Hir", cfg="cfail2")] +#[rustc_clean(label="Hir", cfg="cfail3")] +#[rustc_metadata_dirty(cfg="cfail2")] +#[rustc_metadata_clean(cfg="cfail3")] +#[rustc_inherit_overflow_checks] +pub fn arithmetic_overflow_mult_inherit(val: i32) -> i32 { + val * 2 +} + + +// Arithmetic overflow negation ------------------------------------------------ +#[cfg(cfail1)] +#[rustc_inherit_overflow_checks] +pub fn arithmetic_overflow_negation_inherit(val: i32) -> i32 { + -val +} + +#[cfg(not(cfail1))] +#[rustc_dirty(label="Hir", cfg="cfail2")] +#[rustc_clean(label="Hir", cfg="cfail3")] +#[rustc_metadata_dirty(cfg="cfail2")] +#[rustc_metadata_clean(cfg="cfail3")] +#[rustc_inherit_overflow_checks] +pub fn arithmetic_overflow_negation_inherit(val: i32) -> i32 { + -val +} + + +// Division by zero ------------------------------------------------------------ +#[cfg(cfail1)] +pub fn division_by_zero(val: i32) -> i32 { + 2 / val +} + +#[cfg(not(cfail1))] +#[rustc_dirty(label="Hir", cfg="cfail2")] +#[rustc_clean(label="Hir", cfg="cfail3")] +#[rustc_metadata_dirty(cfg="cfail2")] +#[rustc_metadata_clean(cfg="cfail3")] +pub fn division_by_zero(val: i32) -> i32 { + 2 / val +} + +// Division by zero ------------------------------------------------------------ +#[cfg(cfail1)] +pub fn mod_by_zero(val: i32) -> i32 { + 2 % val +} + +#[cfg(not(cfail1))] +#[rustc_dirty(label="Hir", cfg="cfail2")] +#[rustc_clean(label="Hir", cfg="cfail3")] +#[rustc_metadata_dirty(cfg="cfail2")] +#[rustc_metadata_clean(cfg="cfail3")] +pub fn mod_by_zero(val: i32) -> i32 { + 2 % val +} + + + +// THE FOLLOWING ITEMS SHOULD NOT BE INFLUENCED BY THEIR SOURCE LOCATION + +// bitwise --------------------------------------------------------------------- +#[cfg(cfail1)] +pub fn bitwise(val: i32) -> i32 { + !val & 0x101010101 | 0x45689 ^ 0x2372382 << 1 >> 1 +} + +#[cfg(not(cfail1))] +#[rustc_clean(label="Hir", cfg="cfail2")] +#[rustc_clean(label="Hir", cfg="cfail3")] +#[rustc_metadata_clean(cfg="cfail2")] +#[rustc_metadata_clean(cfg="cfail3")] +pub fn bitwise(val: i32) -> i32 { + !val & 0x101010101 | 0x45689 ^ 0x2372382 << 1 >> 1 +} + + +// logical --------------------------------------------------------------------- +#[cfg(cfail1)] +pub fn logical(val1: bool, val2: bool, val3: bool) -> bool { + val1 && val2 || val3 +} + +#[cfg(not(cfail1))] +#[rustc_clean(label="Hir", cfg="cfail2")] +#[rustc_clean(label="Hir", cfg="cfail3")] +#[rustc_metadata_clean(cfg="cfail2")] +#[rustc_metadata_clean(cfg="cfail3")] +pub fn logical(val1: bool, val2: bool, val3: bool) -> bool { + val1 && val2 || val3 +} + +// Arithmetic overflow plus ---------------------------------------------------- +#[cfg(cfail1)] +pub fn arithmetic_overflow_plus(val: i32) -> i32 { + val + 1 +} + +#[cfg(not(cfail1))] +#[rustc_clean(label="Hir", cfg="cfail2")] +#[rustc_clean(label="Hir", cfg="cfail3")] +#[rustc_metadata_clean(cfg="cfail2")] +#[rustc_metadata_clean(cfg="cfail3")] +pub fn arithmetic_overflow_plus(val: i32) -> i32 { + val + 1 +} + + +// Arithmetic overflow minus ---------------------------------------------------- +#[cfg(cfail1)] +pub fn arithmetic_overflow_minus(val: i32) -> i32 { + val - 1 +} + +#[cfg(not(cfail1))] +#[rustc_clean(label="Hir", cfg="cfail2")] +#[rustc_clean(label="Hir", cfg="cfail3")] +#[rustc_metadata_clean(cfg="cfail2")] +#[rustc_metadata_clean(cfg="cfail3")] +pub fn arithmetic_overflow_minus(val: i32) -> i32 { + val - 1 +} + + +// Arithmetic overflow mult ---------------------------------------------------- +#[cfg(cfail1)] +pub fn arithmetic_overflow_mult(val: i32) -> i32 { + val * 2 +} + +#[cfg(not(cfail1))] +#[rustc_clean(label="Hir", cfg="cfail2")] +#[rustc_clean(label="Hir", cfg="cfail3")] +#[rustc_metadata_clean(cfg="cfail2")] +#[rustc_metadata_clean(cfg="cfail3")] +pub fn arithmetic_overflow_mult(val: i32) -> i32 { + val * 2 +} + + +// Arithmetic overflow negation ------------------------------------------------ +#[cfg(cfail1)] +pub fn arithmetic_overflow_negation(val: i32) -> i32 { + -val +} + +#[cfg(not(cfail1))] +#[rustc_clean(label="Hir", cfg="cfail2")] +#[rustc_clean(label="Hir", cfg="cfail3")] +#[rustc_metadata_clean(cfg="cfail2")] +#[rustc_metadata_clean(cfg="cfail3")] +pub fn arithmetic_overflow_negation(val: i32) -> i32 { + -val +} diff --git a/src/test/incremental/hashes/statics.rs b/src/test/incremental/hashes/statics.rs new file mode 100644 index 0000000000..ac67e43490 --- /dev/null +++ b/src/test/incremental/hashes/statics.rs @@ -0,0 +1,185 @@ +// Copyright 2016 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + + +// This test case tests the incremental compilation hash (ICH) implementation +// for statics. + +// The general pattern followed here is: Change one thing between rev1 and rev2 +// and make sure that the hash has changed, then change nothing between rev2 and +// rev3 and make sure that the hash has not changed. + +// must-compile-successfully +// revisions: cfail1 cfail2 cfail3 +// compile-flags: -Z query-dep-graph + +#![allow(warnings)] +#![feature(rustc_attrs)] +#![feature(linkage)] +#![feature(thread_local)] +#![crate_type="rlib"] + + +// Change static visibility --------------------------------------------------- +#[cfg(cfail1)] +static STATIC_VISIBILITY: u8 = 0; + +#[cfg(not(cfail1))] +#[rustc_dirty(label="Hir", cfg="cfail2")] +#[rustc_clean(label="Hir", cfg="cfail3")] +#[rustc_metadata_dirty(cfg="cfail2")] +#[rustc_metadata_clean(cfg="cfail3")] +pub static STATIC_VISIBILITY: u8 = 0; + + +// Change static mutability --------------------------------------------------- +#[cfg(cfail1)] +static STATIC_MUTABILITY: u8 = 0; + +#[cfg(not(cfail1))] +#[rustc_dirty(label="Hir", cfg="cfail2")] +#[rustc_clean(label="Hir", cfg="cfail3")] +#[rustc_metadata_dirty(cfg="cfail2")] +#[rustc_metadata_clean(cfg="cfail3")] +static mut STATIC_MUTABILITY: u8 = 0; + + +// Add linkage attribute ------------------------------------------------------ +#[cfg(cfail1)] +static STATIC_LINKAGE: u8 = 0; + +#[cfg(not(cfail1))] +#[rustc_dirty(label="Hir", cfg="cfail2")] +#[rustc_clean(label="Hir", cfg="cfail3")] +#[rustc_metadata_dirty(cfg="cfail2")] +#[rustc_metadata_clean(cfg="cfail3")] +#[linkage="weak_odr"] +static STATIC_LINKAGE: u8 = 0; + + +// Add no_mangle attribute ---------------------------------------------------- +#[cfg(cfail1)] +static STATIC_NO_MANGLE: u8 = 0; + +#[cfg(not(cfail1))] +#[rustc_dirty(label="Hir", cfg="cfail2")] +#[rustc_clean(label="Hir", cfg="cfail3")] +#[rustc_metadata_dirty(cfg="cfail2")] +#[rustc_metadata_clean(cfg="cfail3")] +#[no_mangle] +static STATIC_NO_MANGLE: u8 = 0; + + +// Add thread_local attribute ------------------------------------------------- +#[cfg(cfail1)] +static STATIC_THREAD_LOCAL: u8 = 0; + +#[cfg(not(cfail1))] +#[rustc_dirty(label="Hir", cfg="cfail2")] +#[rustc_clean(label="Hir", cfg="cfail3")] +#[rustc_metadata_dirty(cfg="cfail2")] +#[rustc_metadata_clean(cfg="cfail3")] +#[thread_local] +static STATIC_THREAD_LOCAL: u8 = 0; + + +// Change type from i16 to u64 ------------------------------------------------ +#[cfg(cfail1)] +static STATIC_CHANGE_TYPE_1: i16 = 0; + +#[cfg(not(cfail1))] +#[rustc_dirty(label="Hir", cfg="cfail2")] +#[rustc_clean(label="Hir", cfg="cfail3")] +#[rustc_metadata_dirty(cfg="cfail2")] +#[rustc_metadata_clean(cfg="cfail3")] +static STATIC_CHANGE_TYPE_1: u64 = 0; + + +// Change type from Option to Option --------------------------------- +#[cfg(cfail1)] +static STATIC_CHANGE_TYPE_2: Option = None; + +#[cfg(not(cfail1))] +#[rustc_dirty(label="Hir", cfg="cfail2")] +#[rustc_clean(label="Hir", cfg="cfail3")] +#[rustc_metadata_dirty(cfg="cfail2")] +#[rustc_metadata_clean(cfg="cfail3")] +static STATIC_CHANGE_TYPE_2: Option = None; + + +// Change value between simple literals --------------------------------------- +#[cfg(cfail1)] +static STATIC_CHANGE_VALUE_1: i16 = 1; + +#[cfg(not(cfail1))] +#[rustc_dirty(label="Hir", cfg="cfail2")] +#[rustc_clean(label="Hir", cfg="cfail3")] +#[rustc_metadata_dirty(cfg="cfail2")] +#[rustc_metadata_clean(cfg="cfail3")] +static STATIC_CHANGE_VALUE_1: i16 = 2; + + +// Change value between expressions ------------------------------------------- +#[cfg(cfail1)] +static STATIC_CHANGE_VALUE_2: i16 = 1 + 1; + +#[cfg(not(cfail1))] +#[rustc_dirty(label="Hir", cfg="cfail2")] +#[rustc_clean(label="Hir", cfg="cfail3")] +#[rustc_metadata_dirty(cfg="cfail2")] +#[rustc_metadata_clean(cfg="cfail3")] +static STATIC_CHANGE_VALUE_2: i16 = 1 + 2; + + +#[cfg(cfail1)] +static STATIC_CHANGE_VALUE_3: i16 = 2 + 3; + +#[cfg(not(cfail1))] +#[rustc_dirty(label="Hir", cfg="cfail2")] +#[rustc_clean(label="Hir", cfg="cfail3")] +#[rustc_metadata_dirty(cfg="cfail2")] +#[rustc_metadata_clean(cfg="cfail3")] +static STATIC_CHANGE_VALUE_3: i16 = 2 * 3; + + +#[cfg(cfail1)] +static STATIC_CHANGE_VALUE_4: i16 = 1 + 2 * 3; + +#[cfg(not(cfail1))] +#[rustc_dirty(label="Hir", cfg="cfail2")] +#[rustc_clean(label="Hir", cfg="cfail3")] +#[rustc_metadata_dirty(cfg="cfail2")] +#[rustc_metadata_clean(cfg="cfail3")] +static STATIC_CHANGE_VALUE_4: i16 = 1 + 2 * 4; + + +// Change type indirectly ----------------------------------------------------- +struct ReferencedType1; +struct ReferencedType2; + +mod static_change_type_indirectly { + #[cfg(cfail1)] + use super::ReferencedType1 as Type; + + #[cfg(not(cfail1))] + use super::ReferencedType2 as Type; + + #[rustc_dirty(label="Hir", cfg="cfail2")] + #[rustc_clean(label="Hir", cfg="cfail3")] + #[rustc_metadata_dirty(cfg="cfail2")] + #[rustc_metadata_clean(cfg="cfail3")] + static STATIC_CHANGE_TYPE_INDIRECTLY_1: Type = Type; + + #[rustc_dirty(label="Hir", cfg="cfail2")] + #[rustc_clean(label="Hir", cfg="cfail3")] + #[rustc_metadata_dirty(cfg="cfail2")] + #[rustc_metadata_clean(cfg="cfail3")] + static STATIC_CHANGE_TYPE_INDIRECTLY_2: Option = None; +} diff --git a/src/test/incremental/hashes/struct_defs.rs b/src/test/incremental/hashes/struct_defs.rs index 74c7797be2..2d79987823 100644 --- a/src/test/incremental/hashes/struct_defs.rs +++ b/src/test/incremental/hashes/struct_defs.rs @@ -236,3 +236,74 @@ struct Visibility; #[rustc_clean(label="Hir", cfg="cfail3")] #[rustc_metadata_clean(cfg="cfail3")] pub struct Visibility; + + + + +struct ReferencedType1; +struct ReferencedType2; + +// Tuple Struct Change Field Type Indirectly ----------------------------------- +mod tuple_struct_change_field_type_indirectly { + #[cfg(cfail1)] + use super::ReferencedType1 as FieldType; + #[cfg(not(cfail1))] + use super::ReferencedType2 as FieldType; + + #[rustc_dirty(label="Hir", cfg="cfail2")] + #[rustc_clean(label="Hir", cfg="cfail3")] + #[rustc_metadata_dirty(cfg="cfail2")] + #[rustc_metadata_clean(cfg="cfail3")] + struct TupleStruct(FieldType); +} + + +// Record Struct Change Field Type Indirectly ----------------------------------- +mod record_struct_change_field_type_indirectly { + #[cfg(cfail1)] + use super::ReferencedType1 as FieldType; + #[cfg(not(cfail1))] + use super::ReferencedType2 as FieldType; + + #[rustc_dirty(label="Hir", cfg="cfail2")] + #[rustc_clean(label="Hir", cfg="cfail3")] + #[rustc_metadata_dirty(cfg="cfail2")] + #[rustc_metadata_clean(cfg="cfail3")] + struct RecordStruct { + _x: FieldType + } +} + + + + +trait ReferencedTrait1 {} +trait ReferencedTrait2 {} + +// Change Trait Bound Indirectly ----------------------------------------------- +mod change_trait_bound_indirectly { + #[cfg(cfail1)] + use super::ReferencedTrait1 as Trait; + #[cfg(not(cfail1))] + use super::ReferencedTrait2 as Trait; + + #[rustc_dirty(label="Hir", cfg="cfail2")] + #[rustc_clean(label="Hir", cfg="cfail3")] + #[rustc_metadata_dirty(cfg="cfail2")] + #[rustc_metadata_clean(cfg="cfail3")] + struct Struct(T); +} + +// Change Trait Bound Indirectly In Where Clause ------------------------------- +mod change_trait_bound_indirectly_in_where_clause { + #[cfg(cfail1)] + use super::ReferencedTrait1 as Trait; + #[cfg(not(cfail1))] + use super::ReferencedTrait2 as Trait; + + #[rustc_dirty(label="Hir", cfg="cfail2")] + #[rustc_clean(label="Hir", cfg="cfail3")] + #[rustc_metadata_dirty(cfg="cfail2")] + #[rustc_metadata_clean(cfg="cfail3")] + struct Struct(T) where T : Trait; +} diff --git a/src/test/incremental/hashes/trait_defs.rs b/src/test/incremental/hashes/trait_defs.rs new file mode 100644 index 0000000000..391c2e75ba --- /dev/null +++ b/src/test/incremental/hashes/trait_defs.rs @@ -0,0 +1,1115 @@ +// Copyright 2016 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + + +// This test case tests the incremental compilation hash (ICH) implementation +// for trait definitions. + +// The general pattern followed here is: Change one thing between rev1 and rev2 +// and make sure that the hash has changed, then change nothing between rev2 and +// rev3 and make sure that the hash has not changed. + +// We also test the ICH for trait definitions exported in metadata. Same as +// above, we want to make sure that the change between rev1 and rev2 also +// results in a change of the ICH for the trait's metadata, and that it stays +// the same between rev2 and rev3. + +// must-compile-successfully +// revisions: cfail1 cfail2 cfail3 +// compile-flags: -Z query-dep-graph + +#![allow(warnings)] +#![feature(rustc_attrs)] +#![crate_type="rlib"] +#![feature(associated_type_defaults)] +#![feature(intrinsics)] +#![feature(associated_consts)] + + +// Change trait visibility -------------------------------------------------------- +#[cfg(cfail1)] +trait TraitVisibility { } + +#[cfg(not(cfail1))] +#[rustc_dirty(label="Hir", cfg="cfail2")] +#[rustc_clean(label="Hir", cfg="cfail3")] +#[rustc_metadata_clean(cfg="cfail3")] +pub trait TraitVisibility { } + + + +// Change trait unsafety ---------------------------------------------------------- +#[cfg(cfail1)] +trait TraitUnsafety { } + +#[cfg(not(cfail1))] +#[rustc_dirty(label="Hir", cfg="cfail2")] +#[rustc_clean(label="Hir", cfg="cfail3")] +#[rustc_metadata_dirty(cfg="cfail2")] +#[rustc_metadata_clean(cfg="cfail3")] +unsafe trait TraitUnsafety { } + + + +// Add method --------------------------------------------------------------------- +#[cfg(cfail1)] +trait TraitAddMethod { +} + +#[cfg(not(cfail1))] +#[rustc_dirty(label="Hir", cfg="cfail2")] +#[rustc_clean(label="Hir", cfg="cfail3")] +#[rustc_metadata_dirty(cfg="cfail2")] +#[rustc_metadata_clean(cfg="cfail3")] +pub trait TraitAddMethod { + fn method(); +} + + + +// Change name of method ---------------------------------------------------------- +#[cfg(cfail1)] +trait TraitChangeMethodName { + fn method(); +} + +#[cfg(not(cfail1))] +#[rustc_dirty(label="Hir", cfg="cfail2")] +#[rustc_clean(label="Hir", cfg="cfail3")] +#[rustc_metadata_dirty(cfg="cfail2")] +#[rustc_metadata_clean(cfg="cfail3")] +trait TraitChangeMethodName { + fn methodChanged(); +} + + + +// Add return type to method ------------------------------------------------------ +#[cfg(cfail1)] +trait TraitAddReturnType { + fn method(); +} + +#[cfg(not(cfail1))] +#[rustc_dirty(label="Hir", cfg="cfail2")] +#[rustc_clean(label="Hir", cfg="cfail3")] +#[rustc_metadata_dirty(cfg="cfail2")] +#[rustc_metadata_clean(cfg="cfail3")] +trait TraitAddReturnType { + fn method() -> u32; +} + + + +// Change return type of method --------------------------------------------------- +#[cfg(cfail1)] +trait TraitChangeReturnType { + fn method() -> u32; +} + +#[cfg(not(cfail1))] +#[rustc_dirty(label="Hir", cfg="cfail2")] +#[rustc_clean(label="Hir", cfg="cfail3")] +#[rustc_metadata_dirty(cfg="cfail2")] +#[rustc_metadata_clean(cfg="cfail3")] +trait TraitChangeReturnType { + fn method() -> u64; +} + + + +// Add parameter to method -------------------------------------------------------- +#[cfg(cfail1)] +trait TraitAddParameterToMethod { + fn method(); +} + +#[cfg(not(cfail1))] +#[rustc_dirty(label="Hir", cfg="cfail2")] +#[rustc_clean(label="Hir", cfg="cfail3")] +#[rustc_metadata_dirty(cfg="cfail2")] +#[rustc_metadata_clean(cfg="cfail3")] +trait TraitAddParameterToMethod { + fn method(a: u32); +} + + + +// Change name of method parameter ------------------------------------------------ +#[cfg(cfail1)] +trait TraitChangeMethodParameterName { + fn method(a: u32); +} + +#[cfg(not(cfail1))] +#[rustc_dirty(label="Hir", cfg="cfail2")] +#[rustc_clean(label="Hir", cfg="cfail3")] +#[rustc_metadata_dirty(cfg="cfail2")] +#[rustc_metadata_clean(cfg="cfail3")] +trait TraitChangeMethodParameterName { + fn method(b: u32); +} + + + +// Change type of method parameter (i32 => i64) ----------------------------------- +#[cfg(cfail1)] +trait TraitChangeMethodParameterType { + fn method(a: i32); +} + +#[cfg(not(cfail1))] +#[rustc_dirty(label="Hir", cfg="cfail2")] +#[rustc_clean(label="Hir", cfg="cfail3")] +#[rustc_metadata_dirty(cfg="cfail2")] +#[rustc_metadata_clean(cfg="cfail3")] +trait TraitChangeMethodParameterType { + fn method(a: i64); +} + + + +// Change type of method parameter (&i32 => &mut i32) ----------------------------- +#[cfg(cfail1)] +trait TraitChangeMethodParameterTypeRef { + fn method(a: &i32); +} + +#[cfg(not(cfail1))] +#[rustc_dirty(label="Hir", cfg="cfail2")] +#[rustc_clean(label="Hir", cfg="cfail3")] +#[rustc_metadata_dirty(cfg="cfail2")] +#[rustc_metadata_clean(cfg="cfail3")] +trait TraitChangeMethodParameterTypeRef { + fn method(a: &mut i32); +} + + + +// Change order of method parameters ---------------------------------------------- +#[cfg(cfail1)] +trait TraitChangeMethodParametersOrder { + fn method(a: i32, b: i64); +} + +#[cfg(not(cfail1))] +#[rustc_dirty(label="Hir", cfg="cfail2")] +#[rustc_clean(label="Hir", cfg="cfail3")] +#[rustc_metadata_dirty(cfg="cfail2")] +#[rustc_metadata_clean(cfg="cfail3")] +trait TraitChangeMethodParametersOrder { + fn method(b: i64, a: i32); +} + + + +// Add default implementation to method ------------------------------------------- +#[cfg(cfail1)] +trait TraitAddMethodDefaultImplementation { + fn method(); +} + +#[cfg(not(cfail1))] +#[rustc_dirty(label="Hir", cfg="cfail2")] +#[rustc_clean(label="Hir", cfg="cfail3")] +#[rustc_metadata_dirty(cfg="cfail2")] +#[rustc_metadata_clean(cfg="cfail3")] +trait TraitAddMethodDefaultImplementation { + fn method() { } +} + + + +// Change order of methods -------------------------------------------------------- +#[cfg(cfail1)] +trait TraitChangeOrderOfMethods { + fn method0(); + fn method1(); +} + +#[cfg(not(cfail1))] +#[rustc_dirty(label="Hir", cfg="cfail2")] +#[rustc_clean(label="Hir", cfg="cfail3")] +#[rustc_metadata_dirty(cfg="cfail2")] +#[rustc_metadata_clean(cfg="cfail3")] +trait TraitChangeOrderOfMethods { + fn method1(); + fn method0(); +} + + + +// Change mode of self parameter -------------------------------------------------- +#[cfg(cfail1)] +trait TraitChangeModeSelfRefToMut { + fn method(&self); +} + +#[cfg(not(cfail1))] +#[rustc_dirty(label="Hir", cfg="cfail2")] +#[rustc_clean(label="Hir", cfg="cfail3")] +#[rustc_metadata_dirty(cfg="cfail2")] +#[rustc_metadata_clean(cfg="cfail3")] +trait TraitChangeModeSelfRefToMut { + fn method(&mut self); +} + + + +#[cfg(cfail1)] +trait TraitChangeModeSelfOwnToMut: Sized { + fn method(self) {} +} + +#[cfg(not(cfail1))] +#[rustc_dirty(label="Hir", cfg="cfail2")] +#[rustc_clean(label="Hir", cfg="cfail3")] +#[rustc_metadata_dirty(cfg="cfail2")] +#[rustc_metadata_clean(cfg="cfail3")] +trait TraitChangeModeSelfOwnToMut: Sized { + fn method(mut self) {} +} + + + +#[cfg(cfail1)] +trait TraitChangeModeSelfOwnToRef { + fn method(self); +} + +#[cfg(not(cfail1))] +#[rustc_dirty(label="Hir", cfg="cfail2")] +#[rustc_clean(label="Hir", cfg="cfail3")] +#[rustc_metadata_dirty(cfg="cfail2")] +#[rustc_metadata_clean(cfg="cfail3")] +trait TraitChangeModeSelfOwnToRef { + fn method(&self); +} + + + +// Add unsafe modifier to method -------------------------------------------------- +#[cfg(cfail1)] +trait TraitAddUnsafeModifier { + fn method(); +} + +#[cfg(not(cfail1))] +#[rustc_dirty(label="Hir", cfg="cfail2")] +#[rustc_clean(label="Hir", cfg="cfail3")] +#[rustc_metadata_dirty(cfg="cfail2")] +#[rustc_metadata_clean(cfg="cfail3")] +trait TraitAddUnsafeModifier { + unsafe fn method(); +} + + + +// Add extern modifier to method -------------------------------------------------- +#[cfg(cfail1)] +trait TraitAddExternModifier { + fn method(); +} + +#[cfg(not(cfail1))] +#[rustc_dirty(label="Hir", cfg="cfail2")] +#[rustc_clean(label="Hir", cfg="cfail3")] +#[rustc_metadata_dirty(cfg="cfail2")] +#[rustc_metadata_clean(cfg="cfail3")] +trait TraitAddExternModifier { + extern fn method(); +} + + + +// Change extern "C" to extern "rust-intrinsic" ----------------------------------- +#[cfg(cfail1)] +trait TraitChangeExternCToRustIntrinsic { + extern "C" fn method(); +} + +#[cfg(not(cfail1))] +#[rustc_dirty(label="Hir", cfg="cfail2")] +#[rustc_clean(label="Hir", cfg="cfail3")] +#[rustc_metadata_dirty(cfg="cfail2")] +#[rustc_metadata_clean(cfg="cfail3")] +trait TraitChangeExternCToRustIntrinsic { + extern "rust-intrinsic" fn method(); +} + + + +// Add type parameter to method --------------------------------------------------- +#[cfg(cfail1)] +trait TraitAddTypeParameterToMethod { + fn method(); +} + +#[cfg(not(cfail1))] +#[rustc_dirty(label="Hir", cfg="cfail2")] +#[rustc_clean(label="Hir", cfg="cfail3")] +#[rustc_metadata_dirty(cfg="cfail2")] +#[rustc_metadata_clean(cfg="cfail3")] +trait TraitAddTypeParameterToMethod { + fn method(); +} + + + +// Add lifetime parameter to method ----------------------------------------------- +#[cfg(cfail1)] +trait TraitAddLifetimeParameterToMethod { + fn method(); +} + +#[cfg(not(cfail1))] +#[rustc_dirty(label="Hir", cfg="cfail2")] +#[rustc_clean(label="Hir", cfg="cfail3")] +#[rustc_metadata_dirty(cfg="cfail2")] +#[rustc_metadata_clean(cfg="cfail3")] +trait TraitAddLifetimeParameterToMethod { + fn method<'a>(); +} + + + +// dummy trait for bound +trait ReferencedTrait0 { } +trait ReferencedTrait1 { } + +// Add trait bound to method type parameter --------------------------------------- +#[cfg(cfail1)] +trait TraitAddTraitBoundToMethodTypeParameter { + fn method(); +} + +#[cfg(not(cfail1))] +#[rustc_dirty(label="Hir", cfg="cfail2")] +#[rustc_clean(label="Hir", cfg="cfail3")] +#[rustc_metadata_dirty(cfg="cfail2")] +#[rustc_metadata_clean(cfg="cfail3")] +trait TraitAddTraitBoundToMethodTypeParameter { + fn method(); +} + + + +// Add builtin bound to method type parameter ------------------------------------- +#[cfg(cfail1)] +trait TraitAddBuiltinBoundToMethodTypeParameter { + fn method(); +} + +#[cfg(not(cfail1))] +#[rustc_dirty(label="Hir", cfg="cfail2")] +#[rustc_clean(label="Hir", cfg="cfail3")] +#[rustc_metadata_dirty(cfg="cfail2")] +#[rustc_metadata_clean(cfg="cfail3")] +trait TraitAddBuiltinBoundToMethodTypeParameter { + fn method(); +} + + + +// Add lifetime bound to method lifetime parameter ------------------------------------ +#[cfg(cfail1)] +trait TraitAddLifetimeBoundToMethodLifetimeParameter { + fn method<'a, 'b>(a: &'a u32, b: &'b u32); +} + +#[cfg(not(cfail1))] +#[rustc_dirty(label="Hir", cfg="cfail2")] +#[rustc_clean(label="Hir", cfg="cfail3")] +#[rustc_metadata_dirty(cfg="cfail2")] +#[rustc_metadata_clean(cfg="cfail3")] +trait TraitAddLifetimeBoundToMethodLifetimeParameter { + fn method<'a, 'b: 'a>(a: &'a u32, b: &'b u32); +} + + + +// Add second trait bound to method type parameter -------------------------------- +#[cfg(cfail1)] +trait TraitAddSecondTraitBoundToMethodTypeParameter { + fn method(); +} + +#[cfg(not(cfail1))] +#[rustc_dirty(label="Hir", cfg="cfail2")] +#[rustc_clean(label="Hir", cfg="cfail3")] +#[rustc_metadata_dirty(cfg="cfail2")] +#[rustc_metadata_clean(cfg="cfail3")] +trait TraitAddSecondTraitBoundToMethodTypeParameter { + fn method(); +} + + + +// Add second builtin bound to method type parameter ------------------------------ +#[cfg(cfail1)] +trait TraitAddSecondBuiltinBoundToMethodTypeParameter { + fn method(); +} + +#[cfg(not(cfail1))] +#[rustc_dirty(label="Hir", cfg="cfail2")] +#[rustc_clean(label="Hir", cfg="cfail3")] +#[rustc_metadata_dirty(cfg="cfail2")] +#[rustc_metadata_clean(cfg="cfail3")] +trait TraitAddSecondBuiltinBoundToMethodTypeParameter { + fn method(); +} + + + +// Add second lifetime bound to method lifetime parameter ----------------------------- +#[cfg(cfail1)] +trait TraitAddSecondLifetimeBoundToMethodLifetimeParameter { + fn method<'a, 'b, 'c: 'a>(a: &'a u32, b: &'b u32, c: &'c u32); +} + +#[cfg(not(cfail1))] +#[rustc_dirty(label="Hir", cfg="cfail2")] +#[rustc_clean(label="Hir", cfg="cfail3")] +#[rustc_metadata_dirty(cfg="cfail2")] +#[rustc_metadata_clean(cfg="cfail3")] +trait TraitAddSecondLifetimeBoundToMethodLifetimeParameter { + fn method<'a, 'b, 'c: 'a + 'b>(a: &'a u32, b: &'b u32, c: &'c u32); +} + + + +// Add associated type ------------------------------------------------------------ +#[cfg(cfail1)] +trait TraitAddAssociatedType { + fn mathod(); +} + +#[cfg(not(cfail1))] +#[rustc_dirty(label="Hir", cfg="cfail2")] +#[rustc_clean(label="Hir", cfg="cfail3")] +#[rustc_metadata_dirty(cfg="cfail2")] +#[rustc_metadata_clean(cfg="cfail3")] +trait TraitAddAssociatedType { + type Associated; + + fn mathod(); +} + + + +// Add trait bound to associated type --------------------------------------------- +#[cfg(cfail1)] +trait TraitAddTraitBoundToAssociatedType { + type Associated; + + fn mathod(); +} + +#[cfg(not(cfail1))] +#[rustc_dirty(label="Hir", cfg="cfail2")] +#[rustc_clean(label="Hir", cfg="cfail3")] +#[rustc_metadata_dirty(cfg="cfail2")] +#[rustc_metadata_clean(cfg="cfail3")] +trait TraitAddTraitBoundToAssociatedType { + type Associated: ReferencedTrait0; + + fn mathod(); +} + + + +// Add lifetime bound to associated type ------------------------------------------ +#[cfg(cfail1)] +trait TraitAddLifetimeBoundToAssociatedType<'a> { + type Associated; + + fn mathod(); +} + +#[cfg(not(cfail1))] +#[rustc_dirty(label="Hir", cfg="cfail2")] +#[rustc_clean(label="Hir", cfg="cfail3")] +#[rustc_metadata_dirty(cfg="cfail2")] +#[rustc_metadata_clean(cfg="cfail3")] +trait TraitAddLifetimeBoundToAssociatedType<'a> { + type Associated: 'a; + + fn mathod(); +} + + + +// Add default to associated type ------------------------------------------------- +#[cfg(cfail1)] +trait TraitAddDefaultToAssociatedType { + type Associated; + + fn mathod(); +} + +#[cfg(not(cfail1))] +#[rustc_dirty(label="Hir", cfg="cfail2")] +#[rustc_clean(label="Hir", cfg="cfail3")] +#[rustc_metadata_dirty(cfg="cfail2")] +#[rustc_metadata_clean(cfg="cfail3")] +trait TraitAddDefaultToAssociatedType { + type Associated = ReferenceType0; + + fn mathod(); +} + + + +// Add associated constant -------------------------------------------------------- +#[cfg(cfail1)] +trait TraitAddAssociatedConstant { + fn mathod(); +} + +#[cfg(not(cfail1))] +#[rustc_dirty(label="Hir", cfg="cfail2")] +#[rustc_clean(label="Hir", cfg="cfail3")] +#[rustc_metadata_dirty(cfg="cfail2")] +#[rustc_metadata_clean(cfg="cfail3")] +trait TraitAddAssociatedConstant { + const Value: u32; + + fn mathod(); +} + + + +// Add initializer to associated constant ----------------------------------------- +#[cfg(cfail1)] +trait TraitAddInitializerToAssociatedConstant { + const Value: u32; + + fn mathod(); +} + +#[cfg(not(cfail1))] +#[rustc_dirty(label="Hir", cfg="cfail2")] +#[rustc_clean(label="Hir", cfg="cfail3")] +#[rustc_metadata_dirty(cfg="cfail2")] +#[rustc_metadata_clean(cfg="cfail3")] +trait TraitAddInitializerToAssociatedConstant { + const Value: u32 = 1; + + fn mathod(); +} + + + +// Change type of associated constant --------------------------------------------- +#[cfg(cfail1)] +trait TraitChangeTypeOfAssociatedConstant { + const Value: u32; + + fn mathod(); +} + +#[cfg(not(cfail1))] +#[rustc_dirty(label="Hir", cfg="cfail2")] +#[rustc_clean(label="Hir", cfg="cfail3")] +#[rustc_metadata_dirty(cfg="cfail2")] +#[rustc_metadata_clean(cfg="cfail3")] +trait TraitChangeTypeOfAssociatedConstant { + const Value: f64; + + fn mathod(); +} + + + +// Add super trait ---------------------------------------------------------------- +#[cfg(cfail1)] +trait TraitAddSuperTrait { } + +#[cfg(not(cfail1))] +#[rustc_dirty(label="Hir", cfg="cfail2")] +#[rustc_clean(label="Hir", cfg="cfail3")] +#[rustc_metadata_dirty(cfg="cfail2")] +#[rustc_metadata_clean(cfg="cfail3")] +trait TraitAddSuperTrait : ReferencedTrait0 { } + + + +// Add builtin bound (Send or Copy) ----------------------------------------------- +#[cfg(cfail1)] +trait TraitAddBuiltiBound { } + +#[cfg(not(cfail1))] +#[rustc_dirty(label="Hir", cfg="cfail2")] +#[rustc_clean(label="Hir", cfg="cfail3")] +#[rustc_metadata_dirty(cfg="cfail2")] +#[rustc_metadata_clean(cfg="cfail3")] +trait TraitAddBuiltiBound : Send { } + + + +// Add 'static lifetime bound to trait -------------------------------------------- +#[cfg(cfail1)] +trait TraitAddStaticLifetimeBound { } + +#[cfg(not(cfail1))] +#[rustc_dirty(label="Hir", cfg="cfail2")] +#[rustc_clean(label="Hir", cfg="cfail3")] +#[rustc_metadata_dirty(cfg="cfail2")] +#[rustc_metadata_clean(cfg="cfail3")] +trait TraitAddStaticLifetimeBound : 'static { } + + + +// Add super trait as second bound ------------------------------------------------ +#[cfg(cfail1)] +trait TraitAddTraitAsSecondBound : ReferencedTrait0 { } + +#[cfg(not(cfail1))] +#[rustc_dirty(label="Hir", cfg="cfail2")] +#[rustc_clean(label="Hir", cfg="cfail3")] +#[rustc_metadata_dirty(cfg="cfail2")] +#[rustc_metadata_clean(cfg="cfail3")] +trait TraitAddTraitAsSecondBound : ReferencedTrait0 + ReferencedTrait1 { } + +#[cfg(cfail1)] +trait TraitAddTraitAsSecondBoundFromBuiltin : Send { } + +#[cfg(not(cfail1))] +#[rustc_dirty(label="Hir", cfg="cfail2")] +#[rustc_clean(label="Hir", cfg="cfail3")] +#[rustc_metadata_dirty(cfg="cfail2")] +#[rustc_metadata_clean(cfg="cfail3")] +trait TraitAddTraitAsSecondBoundFromBuiltin : Send + ReferencedTrait0 { } + + + +// Add builtin bound as second bound ---------------------------------------------- +#[cfg(cfail1)] +trait TraitAddBuiltinBoundAsSecondBound : ReferencedTrait0 { } + +#[cfg(not(cfail1))] +#[rustc_dirty(label="Hir", cfg="cfail2")] +#[rustc_clean(label="Hir", cfg="cfail3")] +#[rustc_metadata_dirty(cfg="cfail2")] +#[rustc_metadata_clean(cfg="cfail3")] +trait TraitAddBuiltinBoundAsSecondBound : ReferencedTrait0 + Send { } + +#[cfg(cfail1)] +trait TraitAddBuiltinBoundAsSecondBoundFromBuiltin : Send { } + +#[cfg(not(cfail1))] +#[rustc_dirty(label="Hir", cfg="cfail2")] +#[rustc_clean(label="Hir", cfg="cfail3")] +#[rustc_metadata_dirty(cfg="cfail2")] +#[rustc_metadata_clean(cfg="cfail3")] +trait TraitAddBuiltinBoundAsSecondBoundFromBuiltin: Send + Copy { } + + + +// Add 'static bounds as second bound --------------------------------------------- +#[cfg(cfail1)] +trait TraitAddStaticBoundAsSecondBound : ReferencedTrait0 { } + +#[cfg(not(cfail1))] +#[rustc_dirty(label="Hir", cfg="cfail2")] +#[rustc_clean(label="Hir", cfg="cfail3")] +#[rustc_metadata_dirty(cfg="cfail2")] +#[rustc_metadata_clean(cfg="cfail3")] +trait TraitAddStaticBoundAsSecondBound : ReferencedTrait0 + 'static { } + +#[cfg(cfail1)] +trait TraitAddStaticBoundAsSecondBoundFromBuiltin : Send { } + +#[cfg(not(cfail1))] +#[rustc_dirty(label="Hir", cfg="cfail2")] +#[rustc_clean(label="Hir", cfg="cfail3")] +#[rustc_metadata_dirty(cfg="cfail2")] +#[rustc_metadata_clean(cfg="cfail3")] +trait TraitAddStaticBoundAsSecondBoundFromBuiltin : Send + 'static { } + + + +// Add type parameter to trait ---------------------------------------------------- +#[cfg(cfail1)] +trait TraitAddTypeParameterToTrait { } + +#[cfg(not(cfail1))] +#[rustc_dirty(label="Hir", cfg="cfail2")] +#[rustc_clean(label="Hir", cfg="cfail3")] +#[rustc_metadata_dirty(cfg="cfail2")] +#[rustc_metadata_clean(cfg="cfail3")] +trait TraitAddTypeParameterToTrait { } + + + +// Add lifetime parameter to trait ------------------------------------------------ +#[cfg(cfail1)] +trait TraitAddLifetimeParameterToTrait { } + +#[cfg(not(cfail1))] +#[rustc_dirty(label="Hir", cfg="cfail2")] +#[rustc_clean(label="Hir", cfg="cfail3")] +#[rustc_metadata_dirty(cfg="cfail2")] +#[rustc_metadata_clean(cfg="cfail3")] +trait TraitAddLifetimeParameterToTrait<'a> { } + + + +// Add trait bound to type parameter of trait ------------------------------------- +#[cfg(cfail1)] +trait TraitAddTraitBoundToTypeParameterOfTrait { } + +#[cfg(not(cfail1))] +#[rustc_dirty(label="Hir", cfg="cfail2")] +#[rustc_clean(label="Hir", cfg="cfail3")] +#[rustc_metadata_dirty(cfg="cfail2")] +#[rustc_metadata_clean(cfg="cfail3")] +trait TraitAddTraitBoundToTypeParameterOfTrait { } + + + +// Add lifetime bound to type parameter of trait ---------------------------------- +#[cfg(cfail1)] +trait TraitAddLifetimeBoundToTypeParameterOfTrait<'a, T> { } + +#[cfg(not(cfail1))] +#[rustc_dirty(label="Hir", cfg="cfail2")] +#[rustc_clean(label="Hir", cfg="cfail3")] +#[rustc_metadata_dirty(cfg="cfail2")] +#[rustc_metadata_clean(cfg="cfail3")] +trait TraitAddLifetimeBoundToTypeParameterOfTrait<'a, T: 'a> { } + + + +// Add lifetime bound to lifetime parameter of trait ------------------------------ +#[cfg(cfail1)] +trait TraitAddLifetimeBoundToLifetimeParameterOfTrait<'a, 'b> { } + +#[cfg(not(cfail1))] +#[rustc_dirty(label="Hir", cfg="cfail2")] +#[rustc_clean(label="Hir", cfg="cfail3")] +#[rustc_metadata_dirty(cfg="cfail2")] +#[rustc_metadata_clean(cfg="cfail3")] +trait TraitAddLifetimeBoundToLifetimeParameterOfTrait<'a: 'b, 'b> { } + + + +// Add builtin bound to type parameter of trait ----------------------------------- +#[cfg(cfail1)] +trait TraitAddBuiltinBoundToTypeParameterOfTrait { } + +#[cfg(not(cfail1))] +#[rustc_dirty(label="Hir", cfg="cfail2")] +#[rustc_clean(label="Hir", cfg="cfail3")] +#[rustc_metadata_dirty(cfg="cfail2")] +#[rustc_metadata_clean(cfg="cfail3")] +trait TraitAddBuiltinBoundToTypeParameterOfTrait { } + + + +// Add second type parameter to trait --------------------------------------------- +#[cfg(cfail1)] +trait TraitAddSecondTypeParameterToTrait { } + +#[cfg(not(cfail1))] +#[rustc_dirty(label="Hir", cfg="cfail2")] +#[rustc_clean(label="Hir", cfg="cfail3")] +#[rustc_metadata_dirty(cfg="cfail2")] +#[rustc_metadata_clean(cfg="cfail3")] +trait TraitAddSecondTypeParameterToTrait { } + + + +// Add second lifetime parameter to trait ----------------------------------------- +#[cfg(cfail1)] +trait TraitAddSecondLifetimeParameterToTrait<'a> { } + +#[cfg(not(cfail1))] +#[rustc_dirty(label="Hir", cfg="cfail2")] +#[rustc_clean(label="Hir", cfg="cfail3")] +#[rustc_metadata_dirty(cfg="cfail2")] +#[rustc_metadata_clean(cfg="cfail3")] +trait TraitAddSecondLifetimeParameterToTrait<'a, 'b> { } + + + +// Add second trait bound to type parameter of trait ------------------------------ +#[cfg(cfail1)] +trait TraitAddSecondTraitBoundToTypeParameterOfTrait { } + +#[cfg(not(cfail1))] +#[rustc_dirty(label="Hir", cfg="cfail2")] +#[rustc_clean(label="Hir", cfg="cfail3")] +#[rustc_metadata_dirty(cfg="cfail2")] +#[rustc_metadata_clean(cfg="cfail3")] +trait TraitAddSecondTraitBoundToTypeParameterOfTrait { } + + + +// Add second lifetime bound to type parameter of trait --------------------------- +#[cfg(cfail1)] +trait TraitAddSecondLifetimeBoundToTypeParameterOfTrait<'a, 'b, T: 'a> { } + +#[cfg(not(cfail1))] +#[rustc_dirty(label="Hir", cfg="cfail2")] +#[rustc_clean(label="Hir", cfg="cfail3")] +#[rustc_metadata_dirty(cfg="cfail2")] +#[rustc_metadata_clean(cfg="cfail3")] +trait TraitAddSecondLifetimeBoundToTypeParameterOfTrait<'a, 'b, T: 'a + 'b> { } + + + +// Add second lifetime bound to lifetime parameter of trait------------------------ +#[cfg(cfail1)] +trait TraitAddSecondLifetimeBoundToLifetimeParameterOfTrait<'a: 'b, 'b, 'c> { } + +#[cfg(not(cfail1))] +#[rustc_dirty(label="Hir", cfg="cfail2")] +#[rustc_clean(label="Hir", cfg="cfail3")] +#[rustc_metadata_dirty(cfg="cfail2")] +#[rustc_metadata_clean(cfg="cfail3")] +trait TraitAddSecondLifetimeBoundToLifetimeParameterOfTrait<'a: 'b + 'c, 'b, 'c> { } + + + +// Add second builtin bound to type parameter of trait ---------------------------- +#[cfg(cfail1)] +trait TraitAddSecondBuiltinBoundToTypeParameterOfTrait { } + +#[cfg(not(cfail1))] +#[rustc_dirty(label="Hir", cfg="cfail2")] +#[rustc_clean(label="Hir", cfg="cfail3")] +#[rustc_metadata_dirty(cfg="cfail2")] +#[rustc_metadata_clean(cfg="cfail3")] +trait TraitAddSecondBuiltinBoundToTypeParameterOfTrait { } + + + +// -------------------------------------------------------------------------------- +struct ReferenceType0 {} +struct ReferenceType1 {} + + + +// Add trait bound to type parameter of trait in where clause---------------------- +#[cfg(cfail1)] +trait TraitAddTraitBoundToTypeParameterOfTraitWhere { } + +#[cfg(not(cfail1))] +#[rustc_dirty(label="Hir", cfg="cfail2")] +#[rustc_clean(label="Hir", cfg="cfail3")] +#[rustc_metadata_dirty(cfg="cfail2")] +#[rustc_metadata_clean(cfg="cfail3")] +trait TraitAddTraitBoundToTypeParameterOfTraitWhere where T: ReferencedTrait0 { } + + + +// Add lifetime bound to type parameter of trait in where clause------------------- +#[cfg(cfail1)] +trait TraitAddLifetimeBoundToTypeParameterOfTraitWhere<'a, T> { } + +#[cfg(not(cfail1))] +#[rustc_dirty(label="Hir", cfg="cfail2")] +#[rustc_clean(label="Hir", cfg="cfail3")] +#[rustc_metadata_dirty(cfg="cfail2")] +#[rustc_metadata_clean(cfg="cfail3")] +trait TraitAddLifetimeBoundToTypeParameterOfTraitWhere<'a, T> where T: 'a { } + + + +// Add lifetime bound to lifetime parameter of trait in where clause--------------- +#[cfg(cfail1)] +trait TraitAddLifetimeBoundToLifetimeParameterOfTraitWhere<'a, 'b> { } + +#[cfg(not(cfail1))] +#[rustc_dirty(label="Hir", cfg="cfail2")] +#[rustc_clean(label="Hir", cfg="cfail3")] +#[rustc_metadata_dirty(cfg="cfail2")] +#[rustc_metadata_clean(cfg="cfail3")] +trait TraitAddLifetimeBoundToLifetimeParameterOfTraitWhere<'a, 'b> where 'a: 'b { } + + + +// Add builtin bound to type parameter of trait in where clause-------------------- +#[cfg(cfail1)] +trait TraitAddBuiltinBoundToTypeParameterOfTraitWhere { } + +#[cfg(not(cfail1))] +#[rustc_dirty(label="Hir", cfg="cfail2")] +#[rustc_clean(label="Hir", cfg="cfail3")] +#[rustc_metadata_dirty(cfg="cfail2")] +#[rustc_metadata_clean(cfg="cfail3")] +trait TraitAddBuiltinBoundToTypeParameterOfTraitWhere where T: Send { } + + + +// Add second trait bound to type parameter of trait in where clause--------------- +#[cfg(cfail1)] +trait TraitAddSecondTraitBoundToTypeParameterOfTraitWhere where T: ReferencedTrait0 { } + +#[cfg(not(cfail1))] +#[rustc_dirty(label="Hir", cfg="cfail2")] +#[rustc_clean(label="Hir", cfg="cfail3")] +#[rustc_metadata_dirty(cfg="cfail2")] +#[rustc_metadata_clean(cfg="cfail3")] +trait TraitAddSecondTraitBoundToTypeParameterOfTraitWhere + where T: ReferencedTrait0 + ReferencedTrait1 { } + + + +// Add second lifetime bound to type parameter of trait in where clause------------ +#[cfg(cfail1)] +trait TraitAddSecondLifetimeBoundToTypeParameterOfTraitWhere<'a, 'b, T> where T: 'a { } + +#[cfg(not(cfail1))] +#[rustc_dirty(label="Hir", cfg="cfail2")] +#[rustc_clean(label="Hir", cfg="cfail3")] +#[rustc_metadata_dirty(cfg="cfail2")] +#[rustc_metadata_clean(cfg="cfail3")] +trait TraitAddSecondLifetimeBoundToTypeParameterOfTraitWhere<'a, 'b, T> where T: 'a + 'b { } + + + +// Add second lifetime bound to lifetime parameter of trait in where clause-------- +#[cfg(cfail1)] +trait TraitAddSecondLifetimeBoundToLifetimeParameterOfTraitWhere<'a, 'b, 'c> where 'a: 'b { } + +#[cfg(not(cfail1))] +#[rustc_dirty(label="Hir", cfg="cfail2")] +#[rustc_clean(label="Hir", cfg="cfail3")] +#[rustc_metadata_dirty(cfg="cfail2")] +#[rustc_metadata_clean(cfg="cfail3")] +trait TraitAddSecondLifetimeBoundToLifetimeParameterOfTraitWhere<'a, 'b, 'c> where 'a: 'b + 'c { } + + + +// Add second builtin bound to type parameter of trait in where clause------------- +#[cfg(cfail1)] +trait TraitAddSecondBuiltinBoundToTypeParameterOfTraitWhere where T: Send { } + +#[cfg(not(cfail1))] +#[rustc_dirty(label="Hir", cfg="cfail2")] +#[rustc_clean(label="Hir", cfg="cfail3")] +#[rustc_metadata_dirty(cfg="cfail2")] +#[rustc_metadata_clean(cfg="cfail3")] +trait TraitAddSecondBuiltinBoundToTypeParameterOfTraitWhere where T: Send + Sync { } + + + +// EDIT: Some more cases ---------------------------------------------------------- + +// Change return type of method indirectly by modifying a use statement------------ +mod change_return_type_of_method_indirectly_use { + #[cfg(cfail1)] + use super::ReferenceType0 as ReturnType; + #[cfg(not(cfail1))] + use super::ReferenceType1 as ReturnType; + + #[rustc_dirty(label="Hir", cfg="cfail2")] + #[rustc_clean(label="Hir", cfg="cfail3")] + #[rustc_metadata_dirty(cfg="cfail2")] + #[rustc_metadata_clean(cfg="cfail3")] + trait TraitChangeReturnType { + fn method() -> ReturnType; + } +} + + + +// Change type of method parameter indirectly by modifying a use statement--------- +mod change_method_parameter_type_indirectly_by_use { + #[cfg(cfail1)] + use super::ReferenceType0 as ArgType; + #[cfg(not(cfail1))] + use super::ReferenceType1 as ArgType; + + #[rustc_dirty(label="Hir", cfg="cfail2")] + #[rustc_clean(label="Hir", cfg="cfail3")] + #[rustc_metadata_dirty(cfg="cfail2")] + #[rustc_metadata_clean(cfg="cfail3")] + trait TraitChangeArgType { + fn method(a: ArgType); + } +} + + + +// Change trait bound of method type parameter indirectly by modifying a use statement +mod change_method_parameter_type_bound_indirectly_by_use { + #[cfg(cfail1)] + use super::ReferencedTrait0 as Bound; + #[cfg(not(cfail1))] + use super::ReferencedTrait1 as Bound; + + #[rustc_dirty(label="Hir", cfg="cfail2")] + #[rustc_clean(label="Hir", cfg="cfail3")] + #[rustc_metadata_dirty(cfg="cfail2")] + #[rustc_metadata_clean(cfg="cfail3")] + trait TraitChangeBoundOfMethodTypeParameter { + fn method(a: T); + } +} + + + +// Change trait bound of method type parameter in where clause indirectly +// by modifying a use statement +mod change_method_parameter_type_bound_indirectly_by_use_where { + #[cfg(cfail1)] + use super::ReferencedTrait0 as Bound; + #[cfg(not(cfail1))] + use super::ReferencedTrait1 as Bound; + + #[rustc_dirty(label="Hir", cfg="cfail2")] + #[rustc_clean(label="Hir", cfg="cfail3")] + #[rustc_metadata_dirty(cfg="cfail2")] + #[rustc_metadata_clean(cfg="cfail3")] + trait TraitChangeBoundOfMethodTypeParameterWhere { + fn method(a: T) where T: Bound; + } +} + + + +// Change trait bound of trait type parameter indirectly by modifying a use statement +mod change_method_type_parameter_bound_indirectly { + #[cfg(cfail1)] + use super::ReferencedTrait0 as Bound; + #[cfg(not(cfail1))] + use super::ReferencedTrait1 as Bound; + + #[rustc_dirty(label="Hir", cfg="cfail2")] + #[rustc_clean(label="Hir", cfg="cfail3")] + #[rustc_metadata_dirty(cfg="cfail2")] + #[rustc_metadata_clean(cfg="cfail3")] + trait TraitChangeTraitBound { + fn method(a: T); + } +} + + + +// Change trait bound of trait type parameter in where clause indirectly +// by modifying a use statement +mod change_method_type_parameter_bound_indirectly_where { + #[cfg(cfail1)] + use super::ReferencedTrait0 as Bound; + #[cfg(not(cfail1))] + use super::ReferencedTrait1 as Bound; + + #[rustc_dirty(label="Hir", cfg="cfail2")] + #[rustc_clean(label="Hir", cfg="cfail3")] + #[rustc_metadata_dirty(cfg="cfail2")] + #[rustc_metadata_clean(cfg="cfail3")] + trait TraitChangeTraitBoundWhere where T: Bound { + fn method(a: T); + } +} diff --git a/src/test/incremental/struct_change_field_name.rs b/src/test/incremental/struct_change_field_name.rs index c27294442e..cb43d12740 100644 --- a/src/test/incremental/struct_change_field_name.rs +++ b/src/test/incremental/struct_change_field_name.rs @@ -39,13 +39,13 @@ pub fn use_X() -> u32 { let x: X = X { x: 22 }; //[cfail2]~^ ERROR struct `X` has no field named `x` x.x as u32 - //[cfail2]~^ ERROR attempted access of field `x` + //[cfail2]~^ ERROR no field `x` on type `X` } #[rustc_dirty(label="TypeckItemBody", cfg="cfail2")] pub fn use_EmbedX(embed: EmbedX) -> u32 { embed.x.x as u32 - //[cfail2]~^ ERROR attempted access of field `x` + //[cfail2]~^ ERROR no field `x` on type `X` } #[rustc_clean(label="TypeckItemBody", cfg="cfail2")] diff --git a/src/test/mir-opt/deaggregator_test.rs b/src/test/mir-opt/deaggregator_test.rs index e57a9674cf..f136d74fa5 100644 --- a/src/test/mir-opt/deaggregator_test.rs +++ b/src/test/mir-opt/deaggregator_test.rs @@ -23,19 +23,19 @@ fn main() {} // END RUST SOURCE // START rustc.node13.Deaggregator.before.mir // bb0: { -// var0 = arg0; // scope 0 at main.rs:8:8: 8:9 -// tmp0 = var0; // scope 1 at main.rs:9:14: 9:15 -// return = Baz { x: tmp0, y: const F32(0), z: const false }; // scope ... -// goto -> bb1; // scope 1 at main.rs:8:1: 10:2 +// _2 = _1; +// _3 = _2; +// _0 = Baz { x: _3, y: const F32(0), z: const false }; +// return; // } // END rustc.node13.Deaggregator.before.mir // START rustc.node13.Deaggregator.after.mir // bb0: { -// var0 = arg0; // scope 0 at main.rs:8:8: 8:9 -// tmp0 = var0; // scope 1 at main.rs:9:14: 9:15 -// (return.0: usize) = tmp0; // scope 1 at main.rs:9:5: 9:34 -// (return.1: f32) = const F32(0); // scope 1 at main.rs:9:5: 9:34 -// (return.2: bool) = const false; // scope 1 at main.rs:9:5: 9:34 -// goto -> bb1; // scope 1 at main.rs:8:1: 10:2 +// _2 = _1; +// _3 = _2; +// (_0.0: usize) = _3; +// (_0.1: f32) = const F32(0); +// (_0.2: bool) = const false; +// return; // } -// END rustc.node13.Deaggregator.after.mir \ No newline at end of file +// END rustc.node13.Deaggregator.after.mir diff --git a/src/test/mir-opt/deaggregator_test_enum.rs b/src/test/mir-opt/deaggregator_test_enum.rs index ccfa760a28..25fa0e9083 100644 --- a/src/test/mir-opt/deaggregator_test_enum.rs +++ b/src/test/mir-opt/deaggregator_test_enum.rs @@ -28,18 +28,18 @@ fn main() { // END RUST SOURCE // START rustc.node10.Deaggregator.before.mir // bb0: { -// var0 = arg0; // scope 0 at main.rs:7:8: 7:9 -// tmp0 = var0; // scope 1 at main.rs:8:19: 8:20 -// return = Baz::Foo { x: tmp0 }; // scope 1 at main.rs:8:5: 8:21 -// goto -> bb1; // scope 1 at main.rs:7:1: 9:2 +// _2 = _1; +// _3 = _2; +// _0 = Baz::Foo { x: _3 }; +// return; // } // END rustc.node10.Deaggregator.before.mir // START rustc.node10.Deaggregator.after.mir // bb0: { -// var0 = arg0; // scope 0 at main.rs:7:8: 7:9 -// tmp0 = var0; // scope 1 at main.rs:8:19: 8:20 -// ((return as Foo).0: usize) = tmp0; // scope 1 at main.rs:8:5: 8:21 -// discriminant(return) = 1; // scope 1 at main.rs:8:5: 8:21 -// goto -> bb1; // scope 1 at main.rs:7:1: 9:2 +// _2 = _1; +// _3 = _2; +// ((_0 as Foo).0: usize) = _3; +// discriminant(_0) = 1; +// return; // } -// END rustc.node10.Deaggregator.after.mir \ No newline at end of file +// END rustc.node10.Deaggregator.after.mir diff --git a/src/test/mir-opt/simplify_if.rs b/src/test/mir-opt/simplify_if.rs index dd6a857960..7239e32357 100644 --- a/src/test/mir-opt/simplify_if.rs +++ b/src/test/mir-opt/simplify_if.rs @@ -17,11 +17,11 @@ fn main() { // END RUST SOURCE // START rustc.node4.SimplifyBranches.initial-before.mir // bb0: { -// if(const false) -> [true: bb1, false: bb2]; // scope 0 at simplify_if.rs:12:5: 14:6 +// if(const false) -> [true: bb1, false: bb2]; // } // END rustc.node4.SimplifyBranches.initial-before.mir // START rustc.node4.SimplifyBranches.initial-after.mir // bb0: { -// goto -> bb2; // scope 0 at simplify_if.rs:12:5: 14:6 +// goto -> bb2; // } -// END rustc.node4.SimplifyBranches.initial-after.mir \ No newline at end of file +// END rustc.node4.SimplifyBranches.initial-after.mir diff --git a/src/test/mir-opt/storage_ranges.rs b/src/test/mir-opt/storage_ranges.rs index 4ed0c8bc9f..933bfa8df2 100644 --- a/src/test/mir-opt/storage_ranges.rs +++ b/src/test/mir-opt/storage_ranges.rs @@ -21,27 +21,23 @@ fn main() { // END RUST SOURCE // START rustc.node4.TypeckMir.before.mir // bb0: { -// StorageLive(var0); // scope 0 at storage_ranges.rs:14:9: 14:10 -// var0 = const 0i32; // scope 0 at storage_ranges.rs:14:13: 14:14 -// StorageLive(var1); // scope 1 at storage_ranges.rs:16:13: 16:14 -// StorageLive(tmp1); // scope 1 at storage_ranges.rs:16:18: 16:25 -// StorageLive(tmp2); // scope 1 at storage_ranges.rs:16:23: 16:24 -// tmp2 = var0; // scope 1 at storage_ranges.rs:16:23: 16:24 -// tmp1 = std::option::Option::Some(tmp2,); // scope 1 at storage_ranges.rs:16:18: 16:25 -// var1 = &tmp1; // scope 1 at storage_ranges.rs:16:17: 16:25 -// StorageDead(tmp2); // scope 1 at storage_ranges.rs:16:23: 16:24 -// tmp0 = (); // scope 2 at storage_ranges.rs:15:5: 17:6 -// StorageDead(tmp1); // scope 1 at storage_ranges.rs:16:18: 16:25 -// StorageDead(var1); // scope 1 at storage_ranges.rs:16:13: 16:14 -// StorageLive(var2); // scope 1 at storage_ranges.rs:18:9: 18:10 -// var2 = const 1i32; // scope 1 at storage_ranges.rs:18:13: 18:14 -// return = (); // scope 3 at storage_ranges.rs:13:11: 19:2 -// StorageDead(var2); // scope 1 at storage_ranges.rs:18:9: 18:10 -// StorageDead(var0); // scope 0 at storage_ranges.rs:14:9: 14:10 -// goto -> bb1; // scope 0 at storage_ranges.rs:13:1: 19:2 -// } -// -// bb1: { -// return; // scope 0 at storage_ranges.rs:13:1: 19:2 +// StorageLive(_1); +// _1 = const 0i32; +// StorageLive(_3); +// StorageLive(_4); +// StorageLive(_5); +// _5 = _1; +// _4 = std::option::Option::Some(_5,); +// _3 = &_4; +// StorageDead(_5); +// _2 = (); +// StorageDead(_4); +// StorageDead(_3); +// StorageLive(_6); +// _6 = const 1i32; +// _0 = (); +// StorageDead(_6); +// StorageDead(_1); +// return; // } // END rustc.node4.TypeckMir.before.mir diff --git a/src/test/parse-fail/associated-types-project-from-hrtb-explicit.rs b/src/test/parse-fail/associated-types-project-from-hrtb-explicit.rs index 9c7721589d..70055a1018 100644 --- a/src/test/parse-fail/associated-types-project-from-hrtb-explicit.rs +++ b/src/test/parse-fail/associated-types-project-from-hrtb-explicit.rs @@ -8,7 +8,7 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -// compile-flags: -Z parse-only +// compile-flags: -Z parse-only -Z continue-parse-after-error // Test you can't use a higher-ranked trait bound inside of a qualified // path (just won't parse). diff --git a/src/test/parse-fail/generic-non-trailing-defaults.rs b/src/test/parse-fail/generic-non-trailing-defaults.rs index 26ee6ce80d..2bb593258a 100644 --- a/src/test/parse-fail/generic-non-trailing-defaults.rs +++ b/src/test/parse-fail/generic-non-trailing-defaults.rs @@ -8,7 +8,7 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -// compile-flags: -Z parse-only +// compile-flags: -Z parse-only -Z continue-parse-after-error struct Heap; diff --git a/src/test/parse-fail/issue-10412.rs b/src/test/parse-fail/issue-10412.rs index fc2598d1e9..d723d94c02 100644 --- a/src/test/parse-fail/issue-10412.rs +++ b/src/test/parse-fail/issue-10412.rs @@ -19,7 +19,7 @@ trait Serializable<'self, T> { //~ ERROR lifetimes cannot use keyword names impl<'self> Serializable for &'self str { //~ ERROR lifetimes cannot use keyword names //~^ ERROR lifetimes cannot use keyword names fn serialize(val : &'self str) -> Vec { //~ ERROR lifetimes cannot use keyword names - vec!(1) + vec![1] } fn deserialize(repr: &[u8]) -> &'self str { //~ ERROR lifetimes cannot use keyword names "hi" diff --git a/src/test/parse-fail/issue-17904.rs b/src/test/parse-fail/issue-17904.rs index 580b8c66c7..de5aeb02ab 100644 --- a/src/test/parse-fail/issue-17904.rs +++ b/src/test/parse-fail/issue-17904.rs @@ -8,7 +8,7 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -// compile-flags: -Z parse-only +// compile-flags: -Z parse-only -Z continue-parse-after-error struct Baz where U: Eq(U); //This is parsed as the new Fn* style parenthesis syntax. struct Baz where U: Eq(U) -> R; // Notice this parses as well. diff --git a/src/test/parse-fail/issue-37113.rs b/src/test/parse-fail/issue-37113.rs new file mode 100644 index 0000000000..caf451099d --- /dev/null +++ b/src/test/parse-fail/issue-37113.rs @@ -0,0 +1,21 @@ +// Copyright 2016 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +macro_rules! test_macro { + ( $( $t:ty ),* $(),*) => { + enum SomeEnum { + $( $t, )* //~ ERROR expected identifier, found `String` + }; + }; +} + +fn main() { + test_macro!(String,); +} \ No newline at end of file diff --git a/src/test/parse-fail/lex-bad-octal-literal.rs b/src/test/parse-fail/lex-bad-octal-literal.rs index bf9880cb6c..c8406af52a 100644 --- a/src/test/parse-fail/lex-bad-octal-literal.rs +++ b/src/test/parse-fail/lex-bad-octal-literal.rs @@ -8,6 +8,8 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. +// compile-flags: -Z parse-only -Z continue-parse-after-error + fn main() { 0o18; //~ ERROR invalid digit for a base 8 literal 0o1234_9_5670; //~ ERROR invalid digit for a base 8 literal diff --git a/src/test/parse-fail/lifetime-no-keyword.rs b/src/test/parse-fail/lifetime-no-keyword.rs index 9ca81d9918..a8771ae93a 100644 --- a/src/test/parse-fail/lifetime-no-keyword.rs +++ b/src/test/parse-fail/lifetime-no-keyword.rs @@ -8,7 +8,7 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -// compile-flags: -Z parse-only +// compile-flags: -Z parse-only -Z continue-parse-after-error fn foo<'a>(a: &'a isize) { } fn bar(a: &'static isize) { } diff --git a/src/test/parse-fail/raw-byte-string-literals.rs b/src/test/parse-fail/raw-byte-string-literals.rs index d6be8fce53..2e33f98add 100644 --- a/src/test/parse-fail/raw-byte-string-literals.rs +++ b/src/test/parse-fail/raw-byte-string-literals.rs @@ -8,10 +8,10 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -// compile-flags: -Z parse-only +// compile-flags: -Z parse-only -Z continue-parse-after-error pub fn main() { - br"é"; //~ raw byte string must be ASCII - br##~"a"~##; //~ only `#` is allowed in raw string delimitation + br"é"; //~ ERROR raw byte string must be ASCII + br##~"a"~##; //~ ERROR only `#` is allowed in raw string delimitation } diff --git a/src/test/parse-fail/recover-enum.rs b/src/test/parse-fail/recover-enum.rs new file mode 100644 index 0000000000..7de3ed10c9 --- /dev/null +++ b/src/test/parse-fail/recover-enum.rs @@ -0,0 +1,19 @@ +// Copyright 2016 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +// compile-flags: -Z parse-only -Z continue-parse-after-error + +fn main() { + enum Test { + Very + Bad //~ ERROR found `Bad` + Stuff + } +} diff --git a/src/test/parse-fail/recover-enum2.rs b/src/test/parse-fail/recover-enum2.rs new file mode 100644 index 0000000000..49380a03e1 --- /dev/null +++ b/src/test/parse-fail/recover-enum2.rs @@ -0,0 +1,43 @@ +// Copyright 2016 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +// compile-flags: -Z parse-only -Z continue-parse-after-error + +fn main() { + enum Test { + Var1, + Var2(String), + Var3 { + abc: {}, //~ ERROR: expected type, found `{` + }, + } + + // recover... + let a = 1; + enum Test2 { + Fine, + } + + enum Test3 { + StillFine { + def: i32, + }, + } + + { + // fail again + enum Test4 { + Nope(i32 {}) //~ ERROR: found `{` + //~^ ERROR: found `{` + } + } + // still recover later + let bad_syntax = _; //~ ERROR: found `_` +} diff --git a/src/test/parse-fail/recover-struct.rs b/src/test/parse-fail/recover-struct.rs new file mode 100644 index 0000000000..535dd529c0 --- /dev/null +++ b/src/test/parse-fail/recover-struct.rs @@ -0,0 +1,19 @@ +// Copyright 2016 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +// compile-flags: -Z parse-only -Z continue-parse-after-error + +fn main() { + struct Test { + Very + Bad //~ ERROR found `Bad` + Stuff + } +} diff --git a/src/test/parse-fail/removed-syntax-field-let.rs b/src/test/parse-fail/removed-syntax-field-let.rs index 4e542fd747..6deb3bb2e9 100644 --- a/src/test/parse-fail/removed-syntax-field-let.rs +++ b/src/test/parse-fail/removed-syntax-field-let.rs @@ -8,7 +8,7 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -// compile-flags: -Z parse-only +// compile-flags: -Z parse-only -Z continue-parse-after-error struct s { let foo: (), diff --git a/src/test/parse-fail/removed-syntax-with-2.rs b/src/test/parse-fail/removed-syntax-with-2.rs index c58f42abb5..c4354c0760 100644 --- a/src/test/parse-fail/removed-syntax-with-2.rs +++ b/src/test/parse-fail/removed-syntax-with-2.rs @@ -18,5 +18,5 @@ fn removed_with() { let a = S { foo: (), bar: () }; let b = S { foo: (), with a }; - //~^ ERROR expected `:`, found `a` + //~^ ERROR expected one of `,` or `}`, found `a` } diff --git a/src/test/parse-fail/struct-field-numeric-shorthand.rs b/src/test/parse-fail/struct-field-numeric-shorthand.rs new file mode 100644 index 0000000000..2a5c25d186 --- /dev/null +++ b/src/test/parse-fail/struct-field-numeric-shorthand.rs @@ -0,0 +1,19 @@ +// Copyright 2016 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +// compile-flags: -Z parse-only + +#![feature(field_init_shorthand)] + +struct Rgb(u8, u8, u8); + +fn main() { + let _ = Rgb { 0, 1, 2 }; //~ ERROR expected identifier, found `0` +} diff --git a/src/test/parse-fail/syntax-trait-polarity.rs b/src/test/parse-fail/syntax-trait-polarity.rs index c0d8503438..1971ffeaf2 100644 --- a/src/test/parse-fail/syntax-trait-polarity.rs +++ b/src/test/parse-fail/syntax-trait-polarity.rs @@ -8,7 +8,7 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -// compile-flags: -Z parse-only +// compile-flags: -Z parse-only -Z continue-parse-after-error #![feature(optin_builtin_traits)] diff --git a/src/test/parse-fail/trailing-plus-in-bounds.rs b/src/test/parse-fail/trailing-plus-in-bounds.rs index 4abdbad9a0..44bb1f930c 100644 --- a/src/test/parse-fail/trailing-plus-in-bounds.rs +++ b/src/test/parse-fail/trailing-plus-in-bounds.rs @@ -8,7 +8,7 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -// compile-flags: -Z parse-only +// compile-flags: -Z parse-only -Z continue-parse-after-error use std::fmt::Debug; diff --git a/src/test/parse-fail/trait-bounds-not-on-impl.rs b/src/test/parse-fail/trait-bounds-not-on-impl.rs index 3bd8908d18..b7dcc8a8b3 100644 --- a/src/test/parse-fail/trait-bounds-not-on-impl.rs +++ b/src/test/parse-fail/trait-bounds-not-on-impl.rs @@ -8,7 +8,7 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -// compile-flags: -Z parse-only +// compile-flags: -Z parse-only -Z continue-parse-after-error trait Foo { } diff --git a/src/test/parse-fail/use-as-where-use-ends-with-mod-sep.rs b/src/test/parse-fail/use-as-where-use-ends-with-mod-sep.rs index c1e1cc1c7f..9e16e29ba5 100644 --- a/src/test/parse-fail/use-as-where-use-ends-with-mod-sep.rs +++ b/src/test/parse-fail/use-as-where-use-ends-with-mod-sep.rs @@ -8,7 +8,7 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -// compile-flags: -Z parse-only +// compile-flags: -Z parse-only -Z continue-parse-after-error use std::any:: as foo; //~ ERROR expected identifier, found keyword `as` //~^ ERROR: expected one of `::`, `;`, or `as`, found `foo` diff --git a/src/test/parse-fail/where-clauses-no-bounds-or-predicates.rs b/src/test/parse-fail/where-clauses-no-bounds-or-predicates.rs index 3ac7117634..45165b76c4 100644 --- a/src/test/parse-fail/where-clauses-no-bounds-or-predicates.rs +++ b/src/test/parse-fail/where-clauses-no-bounds-or-predicates.rs @@ -8,7 +8,7 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -// compile-flags: -Z parse-only +// compile-flags: -Z parse-only -Z continue-parse-after-error fn equal1(_: &T, _: &T) -> bool where { //~^ ERROR a `where` clause must have at least one predicate in it diff --git a/src/test/pretty/block-disambig.rs b/src/test/pretty/block-disambig.rs index 5f88f90367..c645a66b70 100644 --- a/src/test/pretty/block-disambig.rs +++ b/src/test/pretty/block-disambig.rs @@ -61,9 +61,9 @@ fn test9() { } fn test10() -> isize { - let regs = vec!(0); + let regs = vec![0]; match true { true => { } _ => { } } regs[0] } -fn test11() -> Vec { if true { } vec!(1, 2) } +fn test11() -> Vec { if true { } vec![1, 2] } diff --git a/src/test/pretty/for-comment.rs b/src/test/pretty/for-comment.rs index af76c1d940..32837fbcf8 100644 --- a/src/test/pretty/for-comment.rs +++ b/src/test/pretty/for-comment.rs @@ -17,6 +17,5 @@ fn f(v: &[isize]) -> isize { for e in v { n = *e; // This comment once triggered pretty printer bug } - n } diff --git a/src/test/pretty/issue-4264.pp b/src/test/pretty/issue-4264.pp index 6ce534d52b..40ff4852e3 100644 --- a/src/test/pretty/issue-4264.pp +++ b/src/test/pretty/issue-4264.pp @@ -38,7 +38,7 @@ pub fn bar() { - ((::std::fmt::format as + (($crate::fmt::format as fn(std::fmt::Arguments<'_>) -> std::string::String {std::fmt::format})(((::std::fmt::Arguments::new_v1 as fn(&[&str], &[std::fmt::ArgumentV1<'_>]) -> std::fmt::Arguments<'_> {std::fmt::Arguments<'_>::new_v1})(({ diff --git a/src/test/run-fail-fulldeps/qquote.rs b/src/test/run-fail-fulldeps/qquote.rs index 1458583ff5..d2a16ac750 100644 --- a/src/test/run-fail-fulldeps/qquote.rs +++ b/src/test/run-fail-fulldeps/qquote.rs @@ -27,7 +27,7 @@ fn main() { let ps = syntax::parse::ParseSess::new(); let mut resolver = syntax::ext::base::DummyResolver; let mut cx = syntax::ext::base::ExtCtxt::new( - &ps, vec![], + &ps, syntax::ext::expand::ExpansionConfig::default("qquote".to_string()), &mut resolver); cx.bt_push(syntax::codemap::ExpnInfo { diff --git a/src/test/run-fail/divide-by-zero.rs b/src/test/run-fail/divide-by-zero.rs index c9c4a88c9b..1f9e069526 100644 --- a/src/test/run-fail/divide-by-zero.rs +++ b/src/test/run-fail/divide-by-zero.rs @@ -8,8 +8,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -// ignore-pretty : (#23623) problems when ending with // comments - // error-pattern:attempt to divide by zero fn main() { diff --git a/src/test/run-fail/glob-use-std.rs b/src/test/run-fail/glob-use-std.rs index 6712b3b065..a7ba283b25 100644 --- a/src/test/run-fail/glob-use-std.rs +++ b/src/test/run-fail/glob-use-std.rs @@ -10,10 +10,6 @@ // Issue #7580 -// ignore-pretty -// -// Expanded pretty printing causes resolve conflicts. - // error-pattern:panic works use std::*; diff --git a/src/test/run-fail/mod-zero.rs b/src/test/run-fail/mod-zero.rs index d2b598a793..641d39e232 100644 --- a/src/test/run-fail/mod-zero.rs +++ b/src/test/run-fail/mod-zero.rs @@ -8,8 +8,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -// ignore-pretty : (#23623) problems when ending with // comments - // error-pattern:attempt to calculate the remainder with a divisor of zero fn main() { diff --git a/src/test/run-fail/overflowing-add.rs b/src/test/run-fail/overflowing-add.rs index acc7676db4..250f0726dc 100644 --- a/src/test/run-fail/overflowing-add.rs +++ b/src/test/run-fail/overflowing-add.rs @@ -8,12 +8,9 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -// ignore-pretty : (#23623) problems when ending with // comments - // error-pattern:thread 'main' panicked at 'attempt to add with overflow' // compile-flags: -C debug-assertions - fn main() { let _x = 200u8 + 200u8 + 200u8; } diff --git a/src/test/run-fail/overflowing-lsh-1.rs b/src/test/run-fail/overflowing-lsh-1.rs index 29ce3b0e6a..baa1e05d55 100644 --- a/src/test/run-fail/overflowing-lsh-1.rs +++ b/src/test/run-fail/overflowing-lsh-1.rs @@ -8,8 +8,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -// ignore-pretty : (#23623) problems when ending with // comments - // error-pattern:thread 'main' panicked at 'attempt to shift left with overflow' // compile-flags: -C debug-assertions diff --git a/src/test/run-fail/overflowing-lsh-2.rs b/src/test/run-fail/overflowing-lsh-2.rs index 62fc9230f3..3438ed2c77 100644 --- a/src/test/run-fail/overflowing-lsh-2.rs +++ b/src/test/run-fail/overflowing-lsh-2.rs @@ -8,8 +8,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -// ignore-pretty : (#23623) problems when ending with // comments - // error-pattern:thread 'main' panicked at 'attempt to shift left with overflow' // compile-flags: -C debug-assertions diff --git a/src/test/run-fail/overflowing-lsh-3.rs b/src/test/run-fail/overflowing-lsh-3.rs index 1bc1703a89..ef5c43db6e 100644 --- a/src/test/run-fail/overflowing-lsh-3.rs +++ b/src/test/run-fail/overflowing-lsh-3.rs @@ -8,8 +8,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -// ignore-pretty : (#23623) problems when ending with // comments - // error-pattern:thread 'main' panicked at 'attempt to shift left with overflow' // compile-flags: -C debug-assertions diff --git a/src/test/run-fail/overflowing-lsh-4.rs b/src/test/run-fail/overflowing-lsh-4.rs index 8de44f25e0..226ece6020 100644 --- a/src/test/run-fail/overflowing-lsh-4.rs +++ b/src/test/run-fail/overflowing-lsh-4.rs @@ -8,8 +8,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -// ignore-pretty : (#23623) problems when ending with // comments - // error-pattern:thread 'main' panicked at 'attempt to shift left with overflow' // compile-flags: -C debug-assertions diff --git a/src/test/run-fail/overflowing-mul.rs b/src/test/run-fail/overflowing-mul.rs index a09c0f06a5..b47d0fc413 100644 --- a/src/test/run-fail/overflowing-mul.rs +++ b/src/test/run-fail/overflowing-mul.rs @@ -8,8 +8,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -// ignore-pretty : (#23623) problems when ending with // comments - // error-pattern:thread 'main' panicked at 'attempt to multiply with overflow' // compile-flags: -C debug-assertions diff --git a/src/test/run-fail/overflowing-neg.rs b/src/test/run-fail/overflowing-neg.rs index 96853fc565..836d7e3731 100644 --- a/src/test/run-fail/overflowing-neg.rs +++ b/src/test/run-fail/overflowing-neg.rs @@ -8,8 +8,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -// ignore-pretty : (#23623) problems when ending with // comments - // error-pattern:thread 'main' panicked at 'attempt to negate with overflow' // compile-flags: -C debug-assertions diff --git a/src/test/run-fail/overflowing-rsh-1.rs b/src/test/run-fail/overflowing-rsh-1.rs index ef4a503cfe..8f198c887e 100644 --- a/src/test/run-fail/overflowing-rsh-1.rs +++ b/src/test/run-fail/overflowing-rsh-1.rs @@ -8,8 +8,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -// ignore-pretty : (#23623) problems when ending with // comments - // error-pattern:thread 'main' panicked at 'attempt to shift right with overflow' // compile-flags: -C debug-assertions diff --git a/src/test/run-fail/overflowing-rsh-2.rs b/src/test/run-fail/overflowing-rsh-2.rs index da072b5a9a..e4f260b2bb 100644 --- a/src/test/run-fail/overflowing-rsh-2.rs +++ b/src/test/run-fail/overflowing-rsh-2.rs @@ -8,8 +8,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -// ignore-pretty : (#23623) problems when ending with // comments - // error-pattern:thread 'main' panicked at 'attempt to shift right with overflow' // compile-flags: -C debug-assertions diff --git a/src/test/run-fail/overflowing-rsh-3.rs b/src/test/run-fail/overflowing-rsh-3.rs index 0b7809402e..11aa98a0c3 100644 --- a/src/test/run-fail/overflowing-rsh-3.rs +++ b/src/test/run-fail/overflowing-rsh-3.rs @@ -8,8 +8,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -// ignore-pretty : (#23623) problems when ending with // comments - // error-pattern:thread 'main' panicked at 'attempt to shift right with overflow' // compile-flags: -C debug-assertions diff --git a/src/test/run-fail/overflowing-rsh-4.rs b/src/test/run-fail/overflowing-rsh-4.rs index 1e0cc18fbd..742720e83c 100644 --- a/src/test/run-fail/overflowing-rsh-4.rs +++ b/src/test/run-fail/overflowing-rsh-4.rs @@ -8,8 +8,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -// ignore-pretty : (#23623) problems when ending with // comments - // error-pattern:thread 'main' panicked at 'attempt to shift right with overflow' // compile-flags: -C debug-assertions diff --git a/src/test/run-fail/overflowing-rsh-5.rs b/src/test/run-fail/overflowing-rsh-5.rs index 690901ff0c..6106fdcb16 100644 --- a/src/test/run-fail/overflowing-rsh-5.rs +++ b/src/test/run-fail/overflowing-rsh-5.rs @@ -8,8 +8,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -// ignore-pretty : (#23623) problems when ending with // comments - // error-pattern:thread 'main' panicked at 'attempt to shift right with overflow' // compile-flags: -C debug-assertions diff --git a/src/test/run-fail/overflowing-rsh-6.rs b/src/test/run-fail/overflowing-rsh-6.rs index 6a6ed4f11f..d419550fcc 100644 --- a/src/test/run-fail/overflowing-rsh-6.rs +++ b/src/test/run-fail/overflowing-rsh-6.rs @@ -8,8 +8,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -// ignore-pretty : (#23623) problems when ending with // comments - // error-pattern:thread 'main' panicked at 'attempt to shift right with overflow' // compile-flags: -C debug-assertions diff --git a/src/test/run-fail/overflowing-sub.rs b/src/test/run-fail/overflowing-sub.rs index 083e8d2446..f94cb31b16 100644 --- a/src/test/run-fail/overflowing-sub.rs +++ b/src/test/run-fail/overflowing-sub.rs @@ -8,8 +8,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -// ignore-pretty : (#23623) problems when ending with // comments - // error-pattern:thread 'main' panicked at 'attempt to subtract with overflow' // compile-flags: -C debug-assertions diff --git a/src/test/run-fail/panic-task-name-none.rs b/src/test/run-fail/panic-task-name-none.rs index ab50503830..36e2a4b86a 100644 --- a/src/test/run-fail/panic-task-name-none.rs +++ b/src/test/run-fail/panic-task-name-none.rs @@ -9,6 +9,7 @@ // except according to those terms. // error-pattern:thread '' panicked at 'test' +// ignore-emscripten Needs threads use std::thread; diff --git a/src/test/run-fail/panic-task-name-owned.rs b/src/test/run-fail/panic-task-name-owned.rs index 2d2371f5ce..4da40c3158 100644 --- a/src/test/run-fail/panic-task-name-owned.rs +++ b/src/test/run-fail/panic-task-name-owned.rs @@ -9,6 +9,7 @@ // except according to those terms. // error-pattern:thread 'owned name' panicked at 'test' +// ignore-emscripten Needs threads. use std::thread::Builder; diff --git a/src/test/run-fail/run-unexported-tests.rs b/src/test/run-fail/run-unexported-tests.rs index 8158333ade..3f75229948 100644 --- a/src/test/run-fail/run-unexported-tests.rs +++ b/src/test/run-fail/run-unexported-tests.rs @@ -11,7 +11,6 @@ // error-pattern:runned an unexported test // compile-flags:--test // check-stdout -// ignore-pretty: does not work well with `--test` mod m { pub fn exported() {} diff --git a/src/test/run-fail/task-spawn-barefn.rs b/src/test/run-fail/task-spawn-barefn.rs index ede055acd6..108430848b 100644 --- a/src/test/run-fail/task-spawn-barefn.rs +++ b/src/test/run-fail/task-spawn-barefn.rs @@ -9,6 +9,7 @@ // except according to those terms. // error-pattern:Ensure that the child thread runs by panicking +// ignore-emscripten Needs threads. use std::thread; diff --git a/src/test/run-fail/test-panic.rs b/src/test/run-fail/test-panic.rs index fa36057025..bb6f4abe1f 100644 --- a/src/test/run-fail/test-panic.rs +++ b/src/test/run-fail/test-panic.rs @@ -11,7 +11,7 @@ // check-stdout // error-pattern:thread 'test_foo' panicked at // compile-flags: --test -// ignore-pretty: does not work well with `--test` +// ignore-emscripten #[test] fn test_foo() { diff --git a/src/test/run-fail/test-should-fail-bad-message.rs b/src/test/run-fail/test-should-fail-bad-message.rs index e18c5d9631..eac9813f18 100644 --- a/src/test/run-fail/test-should-fail-bad-message.rs +++ b/src/test/run-fail/test-should-fail-bad-message.rs @@ -11,7 +11,7 @@ // check-stdout // error-pattern:thread 'test_foo' panicked at // compile-flags: --test -// ignore-pretty: does not work well with `--test` +// ignore-emscripten #[test] #[should_panic(expected = "foobar")] diff --git a/src/test/run-fail/test-tasks-invalid-value.rs b/src/test/run-fail/test-tasks-invalid-value.rs index 94ed641c79..fcf3559e7d 100644 --- a/src/test/run-fail/test-tasks-invalid-value.rs +++ b/src/test/run-fail/test-tasks-invalid-value.rs @@ -14,7 +14,7 @@ // error-pattern:should be a positive integer // compile-flags: --test // exec-env:RUST_TEST_THREADS=foo -// ignore-pretty: does not work well with `--test` +// ignore-emscripten #[test] fn do_nothing() {} diff --git a/src/test/run-make/dep-info-spaces/Makefile b/src/test/run-make/dep-info-spaces/Makefile index eda8cb7008..82686ffdd9 100644 --- a/src/test/run-make/dep-info-spaces/Makefile +++ b/src/test/run-make/dep-info-spaces/Makefile @@ -5,9 +5,12 @@ ifneq ($(shell uname),FreeBSD) ifndef IS_WINDOWS all: - $(RUSTC) --emit link,dep-info --crate-type=lib lib.rs + cp lib.rs $(TMPDIR)/ + cp 'foo foo.rs' $(TMPDIR)/ + cp bar.rs $(TMPDIR)/ + $(RUSTC) --emit link,dep-info --crate-type=lib $(TMPDIR)/lib.rs sleep 1 - touch 'foo foo.rs' + touch $(TMPDIR)/'foo foo.rs' -rm -f $(TMPDIR)/done $(MAKE) -drf Makefile.foo rm $(TMPDIR)/done diff --git a/src/test/run-make/dep-info-spaces/Makefile.foo b/src/test/run-make/dep-info-spaces/Makefile.foo index 2f4cc486d8..80a5d4333c 100644 --- a/src/test/run-make/dep-info-spaces/Makefile.foo +++ b/src/test/run-make/dep-info-spaces/Makefile.foo @@ -1,7 +1,7 @@ -LIB := $(shell $(RUSTC) --print file-names --crate-type=lib lib.rs) +LIB := $(shell $(RUSTC) --print file-names --crate-type=lib $(TMPDIR)/lib.rs) $(TMPDIR)/$(LIB): - $(RUSTC) --emit link,dep-info --crate-type=lib lib.rs + $(RUSTC) --emit link,dep-info --crate-type=lib $(TMPDIR)/lib.rs touch $(TMPDIR)/done -include $(TMPDIR)/lib.d diff --git a/src/test/run-make/issue-19371/foo.rs b/src/test/run-make/issue-19371/foo.rs index 35043bdadd..ed127b017b 100644 --- a/src/test/run-make/issue-19371/foo.rs +++ b/src/test/run-make/issue-19371/foo.rs @@ -67,12 +67,6 @@ fn compile(code: String, output: PathBuf, sysroot: PathBuf) { let (sess, cstore) = basic_sess(sysroot); let cfg = build_configuration(&sess, vec![]); let control = CompileController::basic(); - - compile_input(&sess, &cstore, - cfg, - &Input::Str { name: anon_src(), input: code }, - &None, - &Some(output), - None, - &control); + let input = Input::Str { name: anon_src(), input: code }; + compile_input(&sess, &cstore, &input, &None, &Some(output), None, &control); } diff --git a/src/test/run-make/llvm-phase/test.rs b/src/test/run-make/llvm-phase/test.rs index 19e410fef5..ca58e00785 100644 --- a/src/test/run-make/llvm-phase/test.rs +++ b/src/test/run-make/llvm-phase/test.rs @@ -22,6 +22,7 @@ use rustc_driver::driver::CompileController; use rustc_trans::ModuleSource; use rustc::session::Session; use syntax::codemap::FileLoader; +use std::env; use std::io; use std::path::{PathBuf, Path}; @@ -75,12 +76,14 @@ fn main() { path.pop(); path.pop(); - let args: Vec = + let mut args: Vec = format!("_ _ --sysroot {} --crate-type dylib", path.to_str().unwrap()) .split(' ').map(|s| s.to_string()).collect(); + args.push("--out-dir".to_string()); + args.push(env::var("TMPDIR").unwrap()); - let (result, _) = rustc_driver::run_compiler_with_file_loader( - &args, &mut JitCalls, box JitLoader); + let (result, _) = rustc_driver::run_compiler( + &args, &mut JitCalls, Some(box JitLoader), None); if let Err(n) = result { panic!("Error {}", n); } diff --git a/src/test/run-make/rustc-macro-dep-files/Makefile b/src/test/run-make/rustc-macro-dep-files/Makefile new file mode 100644 index 0000000000..e3a6776c80 --- /dev/null +++ b/src/test/run-make/rustc-macro-dep-files/Makefile @@ -0,0 +1,6 @@ +-include ../tools.mk + +all: + $(RUSTC) foo.rs + $(RUSTC) bar.rs --emit dep-info + grep "proc-macro source" $(TMPDIR)/bar.d && exit 1 || exit 0 diff --git a/src/test/run-make/rustc-macro-dep-files/bar.rs b/src/test/run-make/rustc-macro-dep-files/bar.rs new file mode 100644 index 0000000000..a2db98049d --- /dev/null +++ b/src/test/run-make/rustc-macro-dep-files/bar.rs @@ -0,0 +1,21 @@ +// Copyright 2016 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +#![feature(proc_macro)] + +#[macro_use] +extern crate foo; + +#[derive(A)] +struct A; + +fn main() { + let _b = B; +} diff --git a/src/test/run-make/rustc-macro-dep-files/foo.rs b/src/test/run-make/rustc-macro-dep-files/foo.rs new file mode 100644 index 0000000000..bd9e9158c5 --- /dev/null +++ b/src/test/run-make/rustc-macro-dep-files/foo.rs @@ -0,0 +1,24 @@ +// Copyright 2016 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +#![crate_type = "proc-macro"] +#![feature(proc_macro)] +#![feature(proc_macro_lib)] + +extern crate proc_macro; + +use proc_macro::TokenStream; + +#[proc_macro_derive(A)] +pub fn derive(input: TokenStream) -> TokenStream { + let input = input.to_string(); + assert!(input.contains("struct A;")); + "struct B;".parse().unwrap() +} diff --git a/src/test/run-make/save-analysis/foo.rs b/src/test/run-make/save-analysis/foo.rs index 3f36ebe649..e9ed897bf3 100644 --- a/src/test/run-make/save-analysis/foo.rs +++ b/src/test/run-make/save-analysis/foo.rs @@ -10,7 +10,6 @@ #![ crate_name = "test" ] #![feature(box_syntax)] -#![feature(dotdot_in_tuple_patterns)] #![feature(rustc_private)] extern crate graphviz; diff --git a/src/test/run-make/stable-symbol-names/Makefile b/src/test/run-make/stable-symbol-names/Makefile index da96d1b1dc..c1b14440fa 100644 --- a/src/test/run-make/stable-symbol-names/Makefile +++ b/src/test/run-make/stable-symbol-names/Makefile @@ -1,12 +1,16 @@ -include ../tools.mk -# This test case makes sure that monomorphizations of the same function with the -# same set of generic arguments will have the same symbol names when -# instantiated in different crates. +# The following command will: +# 1. dump the symbols of a library using `nm` +# 2. extract only those lines that we are interested in via `grep` +# 3. from those lines, extract just the symbol name via `sed` +# (symbol names always start with "_ZN" and end with "E") +# 4. sort those symbol names for deterministic comparison +# 5. write the result into a file dump-symbols = nm "$(TMPDIR)/lib$(1).rlib" \ - | grep "some_test_function" \ - | sed "s/^[0-9a-f]\{8,16\}/00000000/" \ + | grep -E "some_test_function|Bar|bar" \ + | sed "s/.*\(_ZN.*E\).*/\1/" \ | sort \ > "$(TMPDIR)/$(1).nm" diff --git a/src/test/run-make/stable-symbol-names/stable-symbol-names1.rs b/src/test/run-make/stable-symbol-names/stable-symbol-names1.rs index 7b2cd85711..5c73ff0fab 100644 --- a/src/test/run-make/stable-symbol-names/stable-symbol-names1.rs +++ b/src/test/run-make/stable-symbol-names/stable-symbol-names1.rs @@ -10,6 +10,20 @@ #![crate_type="rlib"] +pub trait Foo { + fn foo(); +} + +pub struct Bar; + +impl Foo for Bar { + fn foo() {} +} + +pub fn bar() { + Bar::foo::(); +} + pub fn some_test_function(t: T) -> T { t } diff --git a/src/test/run-make/stable-symbol-names/stable-symbol-names2.rs b/src/test/run-make/stable-symbol-names/stable-symbol-names2.rs index ff027d6b46..097dce876a 100644 --- a/src/test/run-make/stable-symbol-names/stable-symbol-names2.rs +++ b/src/test/run-make/stable-symbol-names/stable-symbol-names2.rs @@ -18,3 +18,9 @@ pub fn user() { let x = 2u64; stable_symbol_names1::some_test_function(&x); } + +pub fn trait_impl_test_function() { + use stable_symbol_names1::*; + Bar::foo::(); + bar(); +} diff --git a/src/test/run-make/symbols-are-reasonable/Makefile b/src/test/run-make/symbols-are-reasonable/Makefile index c668ffc583..1c117cf0c9 100644 --- a/src/test/run-make/symbols-are-reasonable/Makefile +++ b/src/test/run-make/symbols-are-reasonable/Makefile @@ -1,7 +1,7 @@ -include ../tools.mk # check that the compile generated symbols for strings, binaries, -# vtables, etc. have semisane names (e.g. `str1234`); it's relatively +# vtables, etc. have semisane names (e.g. `str.1234`); it's relatively # easy to accidentally modify the compiler internals to make them # become things like `str"str"(1234)`. @@ -10,6 +10,6 @@ OUT=$(TMPDIR)/lib.s all: $(RUSTC) lib.rs --emit=asm --crate-type=staticlib # just check for symbol declarations with the names we're expecting. - grep 'str[0-9][0-9]*:' $(OUT) - grep 'byte_str[0-9][0-9]*:' $(OUT) - grep 'vtable[0-9][0-9]*' $(OUT) + grep 'str.[0-9][0-9]*:' $(OUT) + grep 'byte_str.[0-9][0-9]*:' $(OUT) + grep 'vtable.[0-9][0-9]*' $(OUT) diff --git a/src/test/run-make/target-without-atomics/Makefile b/src/test/run-make/target-without-atomics/Makefile new file mode 100644 index 0000000000..48c53a5651 --- /dev/null +++ b/src/test/run-make/target-without-atomics/Makefile @@ -0,0 +1,5 @@ +-include ../tools.mk + +# The target used below doesn't support atomic operations. Verify that's the case +all: + $(RUSTC) --print cfg --target thumbv6m-none-eabi | grep -qv target_has_atomic diff --git a/src/test/run-make/tools.mk b/src/test/run-make/tools.mk index 38afa42a29..1db87d474b 100644 --- a/src/test/run-make/tools.mk +++ b/src/test/run-make/tools.mk @@ -22,9 +22,6 @@ RLIB_GLOB = lib$(1)*.rlib BIN = $(1) UNAME = $(shell uname) -ifneq (,$(findstring MINGW,$(UNAME))) -IS_WINDOWS=1 -endif ifeq ($(UNAME),Darwin) RUN = $(TARGET_RPATH_ENV) $(RUN_BINFILE) diff --git a/src/test/run-make/windows-subsystem/Makefile b/src/test/run-make/windows-subsystem/Makefile new file mode 100644 index 0000000000..34fb5db32f --- /dev/null +++ b/src/test/run-make/windows-subsystem/Makefile @@ -0,0 +1,5 @@ +-include ../tools.mk + +all: + $(RUSTC) windows.rs + $(RUSTC) console.rs diff --git a/src/test/run-make/windows-subsystem/console.rs b/src/test/run-make/windows-subsystem/console.rs new file mode 100644 index 0000000000..3aedb0ecab --- /dev/null +++ b/src/test/run-make/windows-subsystem/console.rs @@ -0,0 +1,15 @@ +// Copyright 2016 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +#![feature(windows_subsystem)] +#![windows_subsystem = "console"] + +fn main() {} + diff --git a/src/test/run-make/windows-subsystem/windows.rs b/src/test/run-make/windows-subsystem/windows.rs new file mode 100644 index 0000000000..5d875a5a1b --- /dev/null +++ b/src/test/run-make/windows-subsystem/windows.rs @@ -0,0 +1,14 @@ +// Copyright 2016 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +#![feature(windows_subsystem)] +#![windows_subsystem = "windows"] + +fn main() {} diff --git a/src/test/run-pass-fulldeps/ast_stmt_expr_attr.rs b/src/test/run-pass-fulldeps/ast_stmt_expr_attr.rs index 64747002a6..a41b34f6a5 100644 --- a/src/test/run-pass-fulldeps/ast_stmt_expr_attr.rs +++ b/src/test/run-pass-fulldeps/ast_stmt_expr_attr.rs @@ -31,10 +31,7 @@ use std::fmt; // Copied out of syntax::util::parser_testing pub fn string_to_parser<'a>(ps: &'a ParseSess, source_str: String) -> Parser<'a> { - new_parser_from_source_str(ps, - Vec::new(), - "bogofile".to_string(), - source_str) + new_parser_from_source_str(ps, "bogofile".to_string(), source_str) } fn with_error_checking_parse<'a, T, F>(s: String, ps: &'a ParseSess, f: F) -> PResult<'a, T> where diff --git a/src/test/run-pass-fulldeps/auxiliary/cond_noprelude_plugin.rs b/src/test/run-pass-fulldeps/auxiliary/cond_noprelude_plugin.rs index 6aee63e285..48919fe876 100644 --- a/src/test/run-pass-fulldeps/auxiliary/cond_noprelude_plugin.rs +++ b/src/test/run-pass-fulldeps/auxiliary/cond_noprelude_plugin.rs @@ -12,13 +12,13 @@ #![feature(plugin)] #![feature(plugin_registrar)] #![feature(rustc_private)] -#![plugin(proc_macro)] +#![plugin(proc_macro_plugin)] extern crate rustc_plugin; -extern crate proc_macro; +extern crate proc_macro_tokens; extern crate syntax; -use proc_macro::build::ident_eq; +use proc_macro_tokens::build::ident_eq; use syntax::ext::base::{ExtCtxt, MacResult}; use syntax::ext::proc_macro_shim::build_block_emitter; diff --git a/src/test/run-pass-fulldeps/auxiliary/cond_plugin.rs b/src/test/run-pass-fulldeps/auxiliary/cond_plugin.rs index 8291c8a1e4..0ea4cec75c 100644 --- a/src/test/run-pass-fulldeps/auxiliary/cond_plugin.rs +++ b/src/test/run-pass-fulldeps/auxiliary/cond_plugin.rs @@ -12,13 +12,13 @@ #![feature(plugin)] #![feature(plugin_registrar)] #![feature(rustc_private)] -#![plugin(proc_macro)] +#![plugin(proc_macro_plugin)] extern crate rustc_plugin; -extern crate proc_macro; +extern crate proc_macro_tokens; extern crate syntax; -use proc_macro::prelude::*; +use proc_macro_tokens::prelude::*; use rustc_plugin::Registry; diff --git a/src/test/run-pass-fulldeps/auxiliary/cond_prelude_plugin.rs b/src/test/run-pass-fulldeps/auxiliary/cond_prelude_plugin.rs index 2d92a0ef18..169c96b438 100644 --- a/src/test/run-pass-fulldeps/auxiliary/cond_prelude_plugin.rs +++ b/src/test/run-pass-fulldeps/auxiliary/cond_prelude_plugin.rs @@ -12,14 +12,14 @@ #![feature(plugin)] #![feature(plugin_registrar)] #![feature(rustc_private)] -#![plugin(proc_macro)] +#![plugin(proc_macro_plugin)] extern crate rustc_plugin; -extern crate proc_macro; +extern crate proc_macro_tokens; extern crate syntax; use syntax::ext::proc_macro_shim::prelude::*; -use proc_macro::prelude::*; +use proc_macro_tokens::prelude::*; use rustc_plugin::Registry; diff --git a/src/test/run-pass-fulldeps/auxiliary/custom_derive_partial_eq.rs b/src/test/run-pass-fulldeps/auxiliary/custom_derive_partial_eq.rs index 956f789dab..e750d1fb1e 100644 --- a/src/test/run-pass-fulldeps/auxiliary/custom_derive_partial_eq.rs +++ b/src/test/run-pass-fulldeps/auxiliary/custom_derive_partial_eq.rs @@ -53,12 +53,12 @@ fn expand_deriving_partial_eq(cx: &mut ExtCtxt, span: Span, mitem: &MetaItem, it } let inline = cx.meta_word(span, InternedString::new("inline")); - let attrs = vec!(cx.attribute(span, inline)); + let attrs = vec![cx.attribute(span, inline)]; let methods = vec![MethodDef { name: "eq", generics: LifetimeBounds::empty(), explicit_self: borrowed_explicit_self(), - args: vec!(borrowed_self()), + args: vec![borrowed_self()], ret_ty: Literal(deriving::generic::ty::Path::new_local("bool")), attributes: attrs, is_unsafe: false, diff --git a/src/test/run-pass-fulldeps/auxiliary/custom_derive_plugin_attr.rs b/src/test/run-pass-fulldeps/auxiliary/custom_derive_plugin_attr.rs index 5df95ba5fa..6b58fee157 100644 --- a/src/test/run-pass-fulldeps/auxiliary/custom_derive_plugin_attr.rs +++ b/src/test/run-pass-fulldeps/auxiliary/custom_derive_plugin_attr.rs @@ -12,7 +12,6 @@ #![feature(plugin_registrar)] #![feature(box_syntax)] -#![feature(dotdot_in_tuple_patterns)] #![feature(rustc_private)] extern crate syntax; diff --git a/src/test/run-pass-fulldeps/auxiliary/dummy_mir_pass.rs b/src/test/run-pass-fulldeps/auxiliary/dummy_mir_pass.rs index f7b046b30c..3bc4a40a39 100644 --- a/src/test/run-pass-fulldeps/auxiliary/dummy_mir_pass.rs +++ b/src/test/run-pass-fulldeps/auxiliary/dummy_mir_pass.rs @@ -19,7 +19,7 @@ extern crate rustc_const_math; extern crate syntax; use rustc::mir::transform::{self, MirPass, MirSource}; -use rustc::mir::repr::{Mir, Literal, Location}; +use rustc::mir::{Mir, Literal, Location}; use rustc::mir::visit::MutVisitor; use rustc::ty::TyCtxt; use rustc::middle::const_val::ConstVal; diff --git a/src/test/run-pass-fulldeps/auxiliary/macro_crate_test.rs b/src/test/run-pass-fulldeps/auxiliary/macro_crate_test.rs index 4885863122..7257444ee8 100644 --- a/src/test/run-pass-fulldeps/auxiliary/macro_crate_test.rs +++ b/src/test/run-pass-fulldeps/auxiliary/macro_crate_test.rs @@ -10,7 +10,6 @@ // force-host -#![feature(dotdot_in_tuple_patterns)] #![feature(plugin_registrar, quote, rustc_private)] extern crate syntax; @@ -60,7 +59,7 @@ fn expand_make_a_1(cx: &mut ExtCtxt, sp: Span, tts: &[TokenTree]) -> Box Box { // Parse an expression and emit it unchanged. - let mut parser = parse::new_parser_from_tts(cx.parse_sess(), cx.cfg(), tts.to_vec()); + let mut parser = parse::new_parser_from_tts(cx.parse_sess(), tts.to_vec()); let expr = parser.parse_expr().unwrap(); MacEager::expr(quote_expr!(&mut *cx, $expr)) } diff --git a/src/test/run-pass-fulldeps/auxiliary/proc_macro_def.rs b/src/test/run-pass-fulldeps/auxiliary/proc_macro_def.rs index 52c38a6ee0..9fce19f46f 100644 --- a/src/test/run-pass-fulldeps/auxiliary/proc_macro_def.rs +++ b/src/test/run-pass-fulldeps/auxiliary/proc_macro_def.rs @@ -10,11 +10,11 @@ #![feature(plugin, plugin_registrar, rustc_private)] -extern crate proc_macro; +extern crate proc_macro_tokens; extern crate rustc_plugin; extern crate syntax; -use proc_macro::prelude::*; +use proc_macro_tokens::prelude::*; use rustc_plugin::Registry; use syntax::ext::base::SyntaxExtension; use syntax::ext::proc_macro_shim::prelude::*; diff --git a/src/test/run-pass-fulldeps/auxiliary/procedural_mbe_matching.rs b/src/test/run-pass-fulldeps/auxiliary/procedural_mbe_matching.rs index 2b50c4fe11..6ac0d5ad1a 100644 --- a/src/test/run-pass-fulldeps/auxiliary/procedural_mbe_matching.rs +++ b/src/test/run-pass-fulldeps/auxiliary/procedural_mbe_matching.rs @@ -18,49 +18,58 @@ extern crate syntax_pos; extern crate rustc; extern crate rustc_plugin; -use syntax::parse::token::{self, str_to_ident, NtExpr, NtPat}; +use syntax::parse::token::{str_to_ident, NtExpr, NtPat}; use syntax::ast::{Pat}; use syntax::tokenstream::{TokenTree}; -use syntax::ext::base::{ExtCtxt, MacResult, DummyResult, MacEager}; +use syntax::ext::base::{ExtCtxt, MacResult, MacEager}; use syntax::ext::build::AstBuilder; use syntax::ext::tt::macro_parser::{MatchedSeq, MatchedNonterminal}; use syntax::ext::tt::macro_parser::{Success, Failure, Error}; +use syntax::ext::tt::macro_parser::parse_failure_msg; use syntax::ptr::P; use syntax_pos::Span; use rustc_plugin::Registry; -fn expand_mbe_matches(cx: &mut ExtCtxt, sp: Span, args: &[TokenTree]) +fn expand_mbe_matches(cx: &mut ExtCtxt, _: Span, args: &[TokenTree]) -> Box { let mbe_matcher = quote_matcher!(cx, $matched:expr, $($pat:pat)|+); + let map = match TokenTree::parse(cx, &mbe_matcher, args) { + Success(map) => map, + Failure(_, tok) => { + panic!("expected Success, but got Failure: {}", parse_failure_msg(tok)); + } + Error(_, s) => { + panic!("expected Success, but got Error: {}", s); + } + }; - let mac_expr = match TokenTree::parse(cx, &mbe_matcher[..], args) { - Success(map) => { - match (&*map[&str_to_ident("matched")], &*map[&str_to_ident("pat")]) { - (&MatchedNonterminal(NtExpr(ref matched_expr)), - &MatchedSeq(ref pats, seq_sp)) => { - let pats: Vec> = pats.iter().map(|pat_nt| - if let &MatchedNonterminal(NtPat(ref pat)) = &**pat_nt { - pat.clone() - } else { - unreachable!() - } - ).collect(); - let arm = cx.arm(seq_sp, pats, cx.expr_bool(seq_sp, true)); + let matched_nt = match *map[&str_to_ident("matched")] { + MatchedNonterminal(ref nt) => nt.clone(), + _ => unreachable!(), + }; - quote_expr!(cx, - match $matched_expr { - $arm - _ => false - } - ) + let mac_expr = match (&*matched_nt, &*map[&str_to_ident("pat")]) { + (&NtExpr(ref matched_expr), &MatchedSeq(ref pats, seq_sp)) => { + let pats: Vec> = pats.iter().map(|pat_nt| { + match **pat_nt { + MatchedNonterminal(ref nt) => match **nt { + NtPat(ref pat) => pat.clone(), + _ => unreachable!(), + }, + _ => unreachable!(), } - _ => unreachable!() - } - } - Failure(_, s) | Error(_, s) => { - panic!("expected Success, but got Error/Failure: {}", s); + }).collect(); + let arm = cx.arm(seq_sp, pats, cx.expr_bool(seq_sp, true)); + + quote_expr!(cx, + match $matched_expr { + $arm + _ => false + } + ) } + _ => unreachable!() }; MacEager::expr(mac_expr) diff --git a/src/test/run-pass-fulldeps/compiler-calls.rs b/src/test/run-pass-fulldeps/compiler-calls.rs index 775ba38004..4a397621ce 100644 --- a/src/test/run-pass-fulldeps/compiler-calls.rs +++ b/src/test/run-pass-fulldeps/compiler-calls.rs @@ -47,7 +47,6 @@ impl<'a> CompilerCalls<'a> for TestCalls { fn late_callback(&mut self, _: &getopts::Matches, _: &Session, - _: &ast::CrateConfig, _: &Input, _: &Option, _: &Option) @@ -86,6 +85,6 @@ fn main() { let mut tc = TestCalls { count: 1 }; // we should never get use this filename, but lets make sure they are valid args. let args = vec!["compiler-calls".to_string(), "foo.rs".to_string()]; - rustc_driver::run_compiler(&args, &mut tc); + rustc_driver::run_compiler(&args, &mut tc, None, None); assert_eq!(tc.count, 30); } diff --git a/src/test/run-pass-fulldeps/custom-derive-partial-eq.rs b/src/test/run-pass-fulldeps/custom-derive-partial-eq.rs index 8cc7ab4219..47f5f8397d 100644 --- a/src/test/run-pass-fulldeps/custom-derive-partial-eq.rs +++ b/src/test/run-pass-fulldeps/custom-derive-partial-eq.rs @@ -10,8 +10,6 @@ // aux-build:custom_derive_partial_eq.rs // ignore-stage1 -// ignore-pretty : (#23623) problems when ending with // comments - #![feature(plugin, custom_derive)] #![plugin(custom_derive_partial_eq)] #![allow(unused)] diff --git a/src/test/run-pass-fulldeps/issue-16992.rs b/src/test/run-pass-fulldeps/issue-16992.rs index a439e2bb25..3ab7f8429e 100644 --- a/src/test/run-pass-fulldeps/issue-16992.rs +++ b/src/test/run-pass-fulldeps/issue-16992.rs @@ -8,7 +8,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -// ignore-pretty // ignore-cross-compile #![feature(quote, rustc_private)] diff --git a/src/test/run-pass-fulldeps/issue-18763-quote-token-tree.rs b/src/test/run-pass-fulldeps/issue-18763-quote-token-tree.rs index 829fdb176b..03311d76e4 100644 --- a/src/test/run-pass-fulldeps/issue-18763-quote-token-tree.rs +++ b/src/test/run-pass-fulldeps/issue-18763-quote-token-tree.rs @@ -9,8 +9,6 @@ // except according to those terms. // ignore-cross-compile -// ignore-pretty: does not work well with `--test` - #![feature(quote, rustc_private)] extern crate syntax; diff --git a/src/test/run-pass-fulldeps/lint-group-plugin.rs b/src/test/run-pass-fulldeps/lint-group-plugin.rs index 21942b84bf..978a78cee4 100644 --- a/src/test/run-pass-fulldeps/lint-group-plugin.rs +++ b/src/test/run-pass-fulldeps/lint-group-plugin.rs @@ -10,8 +10,6 @@ // aux-build:lint_group_plugin_test.rs // ignore-stage1 -// ignore-pretty - #![feature(plugin)] #![plugin(lint_group_plugin_test)] #![allow(dead_code)] diff --git a/src/test/run-pass-fulldeps/lint-plugin-cmdline-load.rs b/src/test/run-pass-fulldeps/lint-plugin-cmdline-load.rs index 2a6daa5040..2e86e11bd6 100644 --- a/src/test/run-pass-fulldeps/lint-plugin-cmdline-load.rs +++ b/src/test/run-pass-fulldeps/lint-plugin-cmdline-load.rs @@ -10,7 +10,6 @@ // aux-build:lint_plugin_test.rs // ignore-stage1 -// ignore-pretty: Random space appears with the pretty test // compile-flags: -Z extra-plugins=lint_plugin_test #![allow(dead_code)] diff --git a/src/test/run-pass-fulldeps/lint-plugin.rs b/src/test/run-pass-fulldeps/lint-plugin.rs index b694a1c332..753ad33bd0 100644 --- a/src/test/run-pass-fulldeps/lint-plugin.rs +++ b/src/test/run-pass-fulldeps/lint-plugin.rs @@ -10,8 +10,6 @@ // aux-build:lint_plugin_test.rs // ignore-stage1 -// ignore-pretty - #![feature(plugin)] #![plugin(lint_plugin_test)] #![allow(dead_code)] diff --git a/src/test/run-pass-fulldeps/macro-crate.rs b/src/test/run-pass-fulldeps/macro-crate.rs index fe2317aabe..9b2e36c8ce 100644 --- a/src/test/run-pass-fulldeps/macro-crate.rs +++ b/src/test/run-pass-fulldeps/macro-crate.rs @@ -17,8 +17,8 @@ #[macro_use] #[no_link] extern crate macro_crate_test; -#[into_multi_foo] #[derive(PartialEq, Clone, Debug)] +#[into_multi_foo] fn foo() -> AnotherFakeTypeThatHadBetterGoAway {} // Check that the `#[into_multi_foo]`-generated `foo2` is configured away diff --git a/src/test/run-pass-fulldeps/macro-quote-1.rs b/src/test/run-pass-fulldeps/macro-quote-1.rs index 4ee775dec0..914da3f746 100644 --- a/src/test/run-pass-fulldeps/macro-quote-1.rs +++ b/src/test/run-pass-fulldeps/macro-quote-1.rs @@ -12,10 +12,10 @@ #![feature(plugin)] #![feature(rustc_private)] -#![plugin(proc_macro)] +#![plugin(proc_macro_plugin)] -extern crate proc_macro; -use proc_macro::prelude::*; +extern crate proc_macro_tokens; +use proc_macro_tokens::prelude::*; extern crate syntax; use syntax::ast::Ident; diff --git a/src/test/run-pass-fulldeps/rustc-macro/add-impl.rs b/src/test/run-pass-fulldeps/proc-macro/add-impl.rs similarity index 96% rename from src/test/run-pass-fulldeps/rustc-macro/add-impl.rs rename to src/test/run-pass-fulldeps/proc-macro/add-impl.rs index 226c082564..e82282f3d8 100644 --- a/src/test/run-pass-fulldeps/rustc-macro/add-impl.rs +++ b/src/test/run-pass-fulldeps/proc-macro/add-impl.rs @@ -10,7 +10,7 @@ // aux-build:add-impl.rs -#![feature(rustc_macro)] +#![feature(proc_macro)] #[macro_use] extern crate add_impl; diff --git a/src/test/compile-fail-fulldeps/rustc-macro/append-impl.rs b/src/test/run-pass-fulldeps/proc-macro/append-impl.rs similarity index 88% rename from src/test/compile-fail-fulldeps/rustc-macro/append-impl.rs rename to src/test/run-pass-fulldeps/proc-macro/append-impl.rs index 1300fe6658..f062111df9 100644 --- a/src/test/compile-fail-fulldeps/rustc-macro/append-impl.rs +++ b/src/test/run-pass-fulldeps/proc-macro/append-impl.rs @@ -10,7 +10,7 @@ // aux-build:append-impl.rs -#![feature(rustc_macro)] +#![feature(proc_macro)] #![allow(warnings)] #[macro_use] @@ -24,7 +24,6 @@ trait Append { Append, Eq)] struct A { -//~^ ERROR: the semantics of constant patterns is not yet settled inner: u32, } diff --git a/src/test/run-pass-fulldeps/rustc-macro/auxiliary/add-impl.rs b/src/test/run-pass-fulldeps/proc-macro/auxiliary/add-impl.rs similarity index 78% rename from src/test/run-pass-fulldeps/rustc-macro/auxiliary/add-impl.rs rename to src/test/run-pass-fulldeps/proc-macro/auxiliary/add-impl.rs index 8aab423af0..99586b0bb4 100644 --- a/src/test/run-pass-fulldeps/rustc-macro/auxiliary/add-impl.rs +++ b/src/test/run-pass-fulldeps/proc-macro/auxiliary/add-impl.rs @@ -10,16 +10,16 @@ // no-prefer-dynamic -#![crate_type = "rustc-macro"] -#![feature(rustc_macro)] -#![feature(rustc_macro_lib)] +#![crate_type = "proc-macro"] +#![feature(proc_macro)] +#![feature(proc_macro_lib)] -extern crate rustc_macro; +extern crate proc_macro; -use rustc_macro::TokenStream; +use proc_macro::TokenStream; -#[rustc_macro_derive(AddImpl)] -// #[cfg(rustc_macro)] +#[proc_macro_derive(AddImpl)] +// #[cfg(proc_macro)] pub fn derive(input: TokenStream) -> TokenStream { (input.to_string() + " impl B { diff --git a/src/test/compile-fail-fulldeps/rustc-macro/auxiliary/append-impl.rs b/src/test/run-pass-fulldeps/proc-macro/auxiliary/append-impl.rs similarity index 80% rename from src/test/compile-fail-fulldeps/rustc-macro/auxiliary/append-impl.rs rename to src/test/run-pass-fulldeps/proc-macro/auxiliary/append-impl.rs index c3d295e02c..27c3d643ca 100644 --- a/src/test/compile-fail-fulldeps/rustc-macro/auxiliary/append-impl.rs +++ b/src/test/run-pass-fulldeps/proc-macro/auxiliary/append-impl.rs @@ -11,15 +11,15 @@ // force-host // no-prefer-dynamic -#![feature(rustc_macro)] -#![feature(rustc_macro_lib)] -#![crate_type = "rustc-macro"] +#![feature(proc_macro)] +#![feature(proc_macro_lib)] +#![crate_type = "proc-macro"] -extern crate rustc_macro; +extern crate proc_macro; -use rustc_macro::TokenStream; +use proc_macro::TokenStream; -#[rustc_macro_derive(Append)] +#[proc_macro_derive(Append)] pub fn derive_a(input: TokenStream) -> TokenStream { let mut input = input.to_string(); input.push_str(" diff --git a/src/test/run-pass-fulldeps/rustc-macro/auxiliary/derive-a.rs b/src/test/run-pass-fulldeps/proc-macro/auxiliary/derive-a.rs similarity index 66% rename from src/test/run-pass-fulldeps/rustc-macro/auxiliary/derive-a.rs rename to src/test/run-pass-fulldeps/proc-macro/auxiliary/derive-a.rs index 4dd6ad88b7..c2de173568 100644 --- a/src/test/run-pass-fulldeps/rustc-macro/auxiliary/derive-a.rs +++ b/src/test/run-pass-fulldeps/proc-macro/auxiliary/derive-a.rs @@ -10,18 +10,18 @@ // no-prefer-dynamic -#![crate_type = "rustc-macro"] -#![feature(rustc_macro)] -#![feature(rustc_macro_lib)] +#![crate_type = "proc-macro"] +#![feature(proc_macro)] +#![feature(proc_macro_lib)] -extern crate rustc_macro; +extern crate proc_macro; -use rustc_macro::TokenStream; +use proc_macro::TokenStream; -#[rustc_macro_derive(A)] +#[proc_macro_derive(A)] pub fn derive(input: TokenStream) -> TokenStream { let input = input.to_string(); assert!(input.contains("struct A;")); - assert!(input.contains("#[derive(Eq, Copy, Clone)]")); - "#[derive(Eq, Copy, Clone)] struct A;".parse().unwrap() + assert!(input.contains("#[derive(Debug, PartialEq, Eq, Copy, Clone)]")); + "#[derive(Debug, PartialEq, Eq, Copy, Clone)] struct A;".parse().unwrap() } diff --git a/src/test/run-pass-fulldeps/rustc-macro/auxiliary/derive-atob.rs b/src/test/run-pass-fulldeps/proc-macro/auxiliary/derive-atob.rs similarity index 73% rename from src/test/run-pass-fulldeps/rustc-macro/auxiliary/derive-atob.rs rename to src/test/run-pass-fulldeps/proc-macro/auxiliary/derive-atob.rs index 5b85e2b2a7..a942adc4c8 100644 --- a/src/test/run-pass-fulldeps/rustc-macro/auxiliary/derive-atob.rs +++ b/src/test/run-pass-fulldeps/proc-macro/auxiliary/derive-atob.rs @@ -10,17 +10,17 @@ // no-prefer-dynamic -#![crate_type = "rustc-macro"] -#![feature(rustc_macro)] -#![feature(rustc_macro_lib)] +#![crate_type = "proc-macro"] +#![feature(proc_macro)] +#![feature(proc_macro_lib)] -extern crate rustc_macro; +extern crate proc_macro; -use rustc_macro::TokenStream; +use proc_macro::TokenStream; -#[rustc_macro_derive(AToB)] +#[proc_macro_derive(AToB)] pub fn derive(input: TokenStream) -> TokenStream { let input = input.to_string(); - assert_eq!(input, "struct A;\n"); + assert_eq!(input, "#[derive(Copy, Clone)]\nstruct A;\n"); "struct B;".parse().unwrap() } diff --git a/src/test/run-pass-fulldeps/rustc-macro/auxiliary/derive-ctod.rs b/src/test/run-pass-fulldeps/proc-macro/auxiliary/derive-ctod.rs similarity index 79% rename from src/test/run-pass-fulldeps/rustc-macro/auxiliary/derive-ctod.rs rename to src/test/run-pass-fulldeps/proc-macro/auxiliary/derive-ctod.rs index 54f8dff509..50f1a390b2 100644 --- a/src/test/run-pass-fulldeps/rustc-macro/auxiliary/derive-ctod.rs +++ b/src/test/run-pass-fulldeps/proc-macro/auxiliary/derive-ctod.rs @@ -10,15 +10,15 @@ // no-prefer-dynamic -#![crate_type = "rustc-macro"] -#![feature(rustc_macro)] -#![feature(rustc_macro_lib)] +#![crate_type = "proc-macro"] +#![feature(proc_macro)] +#![feature(proc_macro_lib)] -extern crate rustc_macro; +extern crate proc_macro; -use rustc_macro::TokenStream; +use proc_macro::TokenStream; -#[rustc_macro_derive(CToD)] +#[proc_macro_derive(CToD)] pub fn derive(input: TokenStream) -> TokenStream { let input = input.to_string(); assert_eq!(input, "struct C;\n"); diff --git a/src/test/run-pass-fulldeps/rustc-macro/auxiliary/derive-same-struct.rs b/src/test/run-pass-fulldeps/proc-macro/auxiliary/derive-same-struct.rs similarity index 80% rename from src/test/run-pass-fulldeps/rustc-macro/auxiliary/derive-same-struct.rs rename to src/test/run-pass-fulldeps/proc-macro/auxiliary/derive-same-struct.rs index d83e352e3b..bd283ca57e 100644 --- a/src/test/run-pass-fulldeps/rustc-macro/auxiliary/derive-same-struct.rs +++ b/src/test/run-pass-fulldeps/proc-macro/auxiliary/derive-same-struct.rs @@ -9,23 +9,23 @@ // except according to those terms. // no-prefer-dynamic -// compile-flags:--crate-type rustc-macro +// compile-flags:--crate-type proc-macro -#![feature(rustc_macro)] -#![feature(rustc_macro_lib)] +#![feature(proc_macro)] +#![feature(proc_macro_lib)] -extern crate rustc_macro; +extern crate proc_macro; -use rustc_macro::TokenStream; +use proc_macro::TokenStream; -#[rustc_macro_derive(AToB)] +#[proc_macro_derive(AToB)] pub fn derive1(input: TokenStream) -> TokenStream { println!("input1: {:?}", input.to_string()); assert_eq!(input.to_string(), "#[derive(BToC)]\nstruct A;\n"); "#[derive(BToC)] struct B;".parse().unwrap() } -#[rustc_macro_derive(BToC)] +#[proc_macro_derive(BToC)] pub fn derive2(input: TokenStream) -> TokenStream { assert_eq!(input.to_string(), "struct B;\n"); "struct C;".parse().unwrap() diff --git a/src/test/run-pass-fulldeps/rustc-macro/auxiliary/expand-with-a-macro.rs b/src/test/run-pass-fulldeps/proc-macro/auxiliary/expand-with-a-macro.rs similarity index 82% rename from src/test/run-pass-fulldeps/rustc-macro/auxiliary/expand-with-a-macro.rs rename to src/test/run-pass-fulldeps/proc-macro/auxiliary/expand-with-a-macro.rs index 96aea407e6..155b125690 100644 --- a/src/test/run-pass-fulldeps/rustc-macro/auxiliary/expand-with-a-macro.rs +++ b/src/test/run-pass-fulldeps/proc-macro/auxiliary/expand-with-a-macro.rs @@ -10,16 +10,16 @@ // no-prefer-dynamic -#![crate_type = "rustc-macro"] -#![feature(rustc_macro)] -#![feature(rustc_macro_lib)] +#![crate_type = "proc-macro"] +#![feature(proc_macro)] +#![feature(proc_macro_lib)] #![deny(warnings)] -extern crate rustc_macro; +extern crate proc_macro; -use rustc_macro::TokenStream; +use proc_macro::TokenStream; -#[rustc_macro_derive(A)] +#[proc_macro_derive(A)] pub fn derive(input: TokenStream) -> TokenStream { let input = input.to_string(); assert!(input.contains("struct A;")); diff --git a/src/test/run-pass-fulldeps/rustc-macro/derive-same-struct.rs b/src/test/run-pass-fulldeps/proc-macro/derive-same-struct.rs similarity index 96% rename from src/test/run-pass-fulldeps/rustc-macro/derive-same-struct.rs rename to src/test/run-pass-fulldeps/proc-macro/derive-same-struct.rs index ee0d594564..b3edc8f1c3 100644 --- a/src/test/run-pass-fulldeps/rustc-macro/derive-same-struct.rs +++ b/src/test/run-pass-fulldeps/proc-macro/derive-same-struct.rs @@ -10,7 +10,7 @@ // aux-build:derive-same-struct.rs -#![feature(rustc_macro)] +#![feature(proc_macro)] #[macro_use] extern crate derive_same_struct; diff --git a/src/test/run-pass-fulldeps/rustc-macro/expand-with-a-macro.rs b/src/test/run-pass-fulldeps/proc-macro/expand-with-a-macro.rs similarity index 96% rename from src/test/run-pass-fulldeps/rustc-macro/expand-with-a-macro.rs rename to src/test/run-pass-fulldeps/proc-macro/expand-with-a-macro.rs index cc59be2d75..16f3535ada 100644 --- a/src/test/run-pass-fulldeps/rustc-macro/expand-with-a-macro.rs +++ b/src/test/run-pass-fulldeps/proc-macro/expand-with-a-macro.rs @@ -11,7 +11,7 @@ // aux-build:expand-with-a-macro.rs // ignore-stage1 -#![feature(rustc_macro)] +#![feature(proc_macro)] #![deny(warnings)] #[macro_use] diff --git a/src/test/run-pass-fulldeps/rustc-macro/load-two.rs b/src/test/run-pass-fulldeps/proc-macro/load-two.rs similarity index 93% rename from src/test/run-pass-fulldeps/rustc-macro/load-two.rs rename to src/test/run-pass-fulldeps/proc-macro/load-two.rs index 1500970f02..431c8c5902 100644 --- a/src/test/run-pass-fulldeps/rustc-macro/load-two.rs +++ b/src/test/run-pass-fulldeps/proc-macro/load-two.rs @@ -11,13 +11,14 @@ // aux-build:derive-atob.rs // aux-build:derive-ctod.rs -#![feature(rustc_macro)] +#![feature(proc_macro)] #[macro_use] extern crate derive_atob; #[macro_use] extern crate derive_ctod; +#[derive(Copy, Clone)] #[derive(AToB)] struct A; diff --git a/src/test/run-pass-fulldeps/rustc-macro/smoke.rs b/src/test/run-pass-fulldeps/proc-macro/smoke.rs similarity index 96% rename from src/test/run-pass-fulldeps/rustc-macro/smoke.rs rename to src/test/run-pass-fulldeps/proc-macro/smoke.rs index 588380f114..cd7edb7264 100644 --- a/src/test/run-pass-fulldeps/rustc-macro/smoke.rs +++ b/src/test/run-pass-fulldeps/proc-macro/smoke.rs @@ -11,7 +11,7 @@ // aux-build:derive-a.rs // ignore-stage1 -#![feature(rustc_macro)] +#![feature(proc_macro)] #[macro_use] extern crate derive_a; diff --git a/src/test/run-pass-fulldeps/qquote.rs b/src/test/run-pass-fulldeps/qquote.rs index 2a53a62a5a..7c0c24163f 100644 --- a/src/test/run-pass-fulldeps/qquote.rs +++ b/src/test/run-pass-fulldeps/qquote.rs @@ -23,7 +23,7 @@ fn main() { let ps = syntax::parse::ParseSess::new(); let mut resolver = syntax::ext::base::DummyResolver; let mut cx = syntax::ext::base::ExtCtxt::new( - &ps, vec![], + &ps, syntax::ext::expand::ExpansionConfig::default("qquote".to_string()), &mut resolver); cx.bt_push(syntax::codemap::ExpnInfo { diff --git a/src/test/run-pass-fulldeps/quote-tokens.rs b/src/test/run-pass-fulldeps/quote-tokens.rs index 710e2fd1d0..9e9b7ce5bf 100644 --- a/src/test/run-pass-fulldeps/quote-tokens.rs +++ b/src/test/run-pass-fulldeps/quote-tokens.rs @@ -9,8 +9,6 @@ // except according to those terms. // ignore-cross-compile -// ignore-pretty: does not work well with `--test` - #![feature(quote, rustc_private)] extern crate syntax; diff --git a/src/test/run-pass-fulldeps/quote-unused-sp-no-warning.rs b/src/test/run-pass-fulldeps/quote-unused-sp-no-warning.rs index 460eab998c..d3be1ddcb8 100644 --- a/src/test/run-pass-fulldeps/quote-unused-sp-no-warning.rs +++ b/src/test/run-pass-fulldeps/quote-unused-sp-no-warning.rs @@ -9,8 +9,6 @@ // except according to those terms. // ignore-cross-compile -// ignore-pretty: does not work well with `--test` - #![feature(quote, rustc_private)] #![deny(unused_variables)] diff --git a/src/test/run-pass-valgrind/cast-enum-with-dtor.rs b/src/test/run-pass-valgrind/cast-enum-with-dtor.rs index 7cf75924a2..2815863fe9 100644 --- a/src/test/run-pass-valgrind/cast-enum-with-dtor.rs +++ b/src/test/run-pass-valgrind/cast-enum-with-dtor.rs @@ -8,8 +8,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -// ignore-pretty : (#23623) problems when ending with // comments - // no-prefer-dynamic #![allow(dead_code)] diff --git a/src/test/run-pass/allocator-override.rs b/src/test/run-pass/allocator-override.rs index d7a8e79bfb..ca2dbdf2b3 100644 --- a/src/test/run-pass/allocator-override.rs +++ b/src/test/run-pass/allocator-override.rs @@ -10,6 +10,7 @@ // no-prefer-dynamic // aux-build:allocator-dummy.rs +// ignore-emscripten #![feature(test)] diff --git a/src/test/run-pass/assignability-trait.rs b/src/test/run-pass/assignability-trait.rs index c364240f4a..bc95d96a8c 100644 --- a/src/test/run-pass/assignability-trait.rs +++ b/src/test/run-pass/assignability-trait.rs @@ -38,7 +38,7 @@ fn length>(x: T) -> usize { } pub fn main() { - let x: Vec = vec!(0,1,2,3); + let x: Vec = vec![0,1,2,3]; // Call a method x.iterate(|y| { assert_eq!(x[*y as usize], *y); true }); // Call a parameterized function diff --git a/src/test/run-pass/associated-types-doubleendediterator-object.rs b/src/test/run-pass/associated-types-doubleendediterator-object.rs index 1661812520..dd19444774 100644 --- a/src/test/run-pass/associated-types-doubleendediterator-object.rs +++ b/src/test/run-pass/associated-types-doubleendediterator-object.rs @@ -25,7 +25,7 @@ fn pairwise_sub(mut t: Box>) -> isize { } fn main() { - let v = vec!(1, 2, 3, 4, 5, 6); + let v = vec![1, 2, 3, 4, 5, 6]; // FIXME (#22405): Replace `Box::new` with `box` here when/if possible. let r = pairwise_sub(Box::new(v.into_iter())); assert_eq!(r, 9); diff --git a/src/test/run-pass/associated-types-iterator-binding.rs b/src/test/run-pass/associated-types-iterator-binding.rs index be854f820d..abd4917cae 100644 --- a/src/test/run-pass/associated-types-iterator-binding.rs +++ b/src/test/run-pass/associated-types-iterator-binding.rs @@ -22,7 +22,7 @@ fn pairwise_sub>(mut t: T) -> isize { } fn main() { - let v = vec!(1, 2, 3, 4, 5, 6); + let v = vec![1, 2, 3, 4, 5, 6]; let r = pairwise_sub(v.into_iter()); assert_eq!(r, 9); } diff --git a/src/test/run-pass/attr-on-generic-formals.rs b/src/test/run-pass/attr-on-generic-formals.rs new file mode 100644 index 0000000000..5985284d84 --- /dev/null +++ b/src/test/run-pass/attr-on-generic-formals.rs @@ -0,0 +1,60 @@ +// Copyright 2016 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +// This test ensures we can attach attributes to the formals in all +// places where generic parameter lists occur, assuming appropriate +// feature gates are enabled. +// +// (We are prefixing all tested features with `rustc_`, to ensure that +// the attributes themselves won't be rejected by the compiler when +// using `rustc_attrs` feature. There is a separate compile-fail/ test +// ensuring that the attribute feature-gating works in this context.) + +#![feature(generic_param_attrs, rustc_attrs)] +#![allow(dead_code)] + +struct StLt<#[rustc_lt_struct] 'a>(&'a u32); +struct StTy<#[rustc_ty_struct] I>(I); + +enum EnLt<#[rustc_lt_enum] 'b> { A(&'b u32), B } +enum EnTy<#[rustc_ty_enum] J> { A(J), B } + +trait TrLt<#[rustc_lt_trait] 'c> { fn foo(&self, _: &'c [u32]) -> &'c u32; } +trait TrTy<#[rustc_ty_trait] K> { fn foo(&self, _: K); } + +type TyLt<#[rustc_lt_type] 'd> = &'d u32; +type TyTy<#[rustc_ty_type] L> = (L, ); + +impl<#[rustc_lt_inherent] 'e> StLt<'e> { } +impl<#[rustc_ty_inherent] M> StTy { } + +impl<#[rustc_lt_impl_for] 'f> TrLt<'f> for StLt<'f> { + fn foo(&self, _: &'f [u32]) -> &'f u32 { loop { } } +} +impl<#[rustc_ty_impl_for] N> TrTy for StTy { + fn foo(&self, _: N) { } +} + +fn f_lt<#[rustc_lt_fn] 'g>(_: &'g [u32]) -> &'g u32 { loop { } } +fn f_ty<#[rustc_ty_fn] O>(_: O) { } + +impl StTy { + fn m_lt<#[rustc_lt_meth] 'h>(_: &'h [u32]) -> &'h u32 { loop { } } + fn m_ty<#[rustc_ty_meth] P>(_: P) { } +} + +fn hof_lt(_: Q) + where Q: for <#[rustc_lt_hof] 'i> Fn(&'i [u32]) -> &'i u32 +{ +} + +fn main() { + +} diff --git a/src/test/run-pass/auto-loop.rs b/src/test/run-pass/auto-loop.rs index babc0db4c3..b0afae79c3 100644 --- a/src/test/run-pass/auto-loop.rs +++ b/src/test/run-pass/auto-loop.rs @@ -11,7 +11,7 @@ pub fn main() { let mut sum = 0; - let xs = vec!(1, 2, 3, 4, 5); + let xs = vec![1, 2, 3, 4, 5]; for x in &xs { sum += *x; } diff --git a/src/test/run-pass/auto-ref-sliceable.rs b/src/test/run-pass/auto-ref-sliceable.rs index 5b12edb427..f6cb314d06 100644 --- a/src/test/run-pass/auto-ref-sliceable.rs +++ b/src/test/run-pass/auto-ref-sliceable.rs @@ -21,7 +21,7 @@ impl Pushable for Vec { } pub fn main() { - let mut v = vec!(1); + let mut v = vec![1]; v.push_val(2); v.push_val(3); assert_eq!(v, [1, 2, 3]); diff --git a/src/test/run-pass/autobind.rs b/src/test/run-pass/autobind.rs index 1f3d17ad55..ed0b9eca0e 100644 --- a/src/test/run-pass/autobind.rs +++ b/src/test/run-pass/autobind.rs @@ -12,7 +12,7 @@ fn f(x: Vec) -> T { return x.into_iter().next().unwrap(); } -fn g(act: F) -> isize where F: FnOnce(Vec) -> isize { return act(vec!(1, 2, 3)); } +fn g(act: F) -> isize where F: FnOnce(Vec) -> isize { return act(vec![1, 2, 3]); } pub fn main() { assert_eq!(g(f), 1); diff --git a/src/test/run-pass/auxiliary/check_static_recursion_foreign_helper.rs b/src/test/run-pass/auxiliary/check_static_recursion_foreign_helper.rs index c0d81cd8e1..cd36a8eedb 100644 --- a/src/test/run-pass/auxiliary/check_static_recursion_foreign_helper.rs +++ b/src/test/run-pass/auxiliary/check_static_recursion_foreign_helper.rs @@ -12,8 +12,8 @@ #![feature(libc)] -#[crate_id = "check_static_recursion_foreign_helper"] -#[crate_type = "lib"] +#![crate_name = "check_static_recursion_foreign_helper"] +#![crate_type = "lib"] extern crate libc; diff --git a/src/test/run-pass/auxiliary/dropck_eyepatch_extern_crate.rs b/src/test/run-pass/auxiliary/dropck_eyepatch_extern_crate.rs new file mode 100644 index 0000000000..1266e589b1 --- /dev/null +++ b/src/test/run-pass/auxiliary/dropck_eyepatch_extern_crate.rs @@ -0,0 +1,61 @@ +// Copyright 2016 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +#![feature(generic_param_attrs)] +#![feature(dropck_eyepatch)] + +// The point of this test is to illustrate that the `#[may_dangle]` +// attribute specifically allows, in the context of a type +// implementing `Drop`, a generic parameter to be instantiated with a +// lifetime that does not strictly outlive the owning type itself, +// and that this attributes effects are preserved when importing +// the type from another crate. +// +// See also dropck-eyepatch.rs for more information about the general +// structure of the test. + +use std::cell::RefCell; + +pub trait Foo { fn foo(&self, _: &str); } + +pub struct Dt(pub &'static str, pub A); +pub struct Dr<'a, B:'a+Foo>(pub &'static str, pub &'a B); +pub struct Pt(pub &'static str, pub A, pub B); +pub struct Pr<'a, 'b, B:'a+'b+Foo>(pub &'static str, pub &'a B, pub &'b B); +pub struct St(pub &'static str, pub A); +pub struct Sr<'a, B:'a+Foo>(pub &'static str, pub &'a B); + +impl Drop for Dt { + fn drop(&mut self) { println!("drop {}", self.0); self.1.foo(self.0); } +} +impl<'a, B: Foo> Drop for Dr<'a, B> { + fn drop(&mut self) { println!("drop {}", self.0); self.1.foo(self.0); } +} +unsafe impl<#[may_dangle] A, B: Foo> Drop for Pt { + // (unsafe to access self.1 due to #[may_dangle] on A) + fn drop(&mut self) { println!("drop {}", self.0); self.2.foo(self.0); } +} +unsafe impl<#[may_dangle] 'a, 'b, B: Foo> Drop for Pr<'a, 'b, B> { + // (unsafe to access self.1 due to #[may_dangle] on 'a) + fn drop(&mut self) { println!("drop {}", self.0); self.2.foo(self.0); } +} + +impl Foo for RefCell { + fn foo(&self, s: &str) { + let s2 = format!("{}|{}", *self.borrow(), s); + *self.borrow_mut() = s2; + } +} + +impl<'a, T:Foo> Foo for &'a T { + fn foo(&self, s: &str) { + (*self).foo(s); + } +} diff --git a/src/test/run-pass/auxiliary/issue-36954.rs b/src/test/run-pass/auxiliary/issue-36954.rs new file mode 100644 index 0000000000..832ee1d7c1 --- /dev/null +++ b/src/test/run-pass/auxiliary/issue-36954.rs @@ -0,0 +1,18 @@ +// Copyright 2016 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +#![feature(const_fn)] +#![crate_type = "lib"] + +const fn foo(i: i32) -> i32 { + i +} + +pub const FOO: i32 = foo(1); diff --git a/src/test/run-pass/backtrace-debuginfo.rs b/src/test/run-pass/backtrace-debuginfo.rs index 838005cbc9..72cf109fd5 100644 --- a/src/test/run-pass/backtrace-debuginfo.rs +++ b/src/test/run-pass/backtrace-debuginfo.rs @@ -16,7 +16,7 @@ // "enable" to 0 instead. // compile-flags:-g -Cllvm-args=-enable-tail-merge=0 -// ignore-pretty as this critically relies on line numbers +// ignore-pretty issue #37195 // ignore-emscripten spawning processes is not supported use std::io; diff --git a/src/test/run-pass/backtrace.rs b/src/test/run-pass/backtrace.rs index f26706d175..c438c17f51 100644 --- a/src/test/run-pass/backtrace.rs +++ b/src/test/run-pass/backtrace.rs @@ -8,7 +8,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -// no-pretty-expanded FIXME #15189 // ignore-android FIXME #17520 // ignore-emscripten spawning processes is not supported // compile-flags:-g diff --git a/src/test/run-pass/block-arg.rs b/src/test/run-pass/block-arg.rs index 2f530331a2..7fca4bccab 100644 --- a/src/test/run-pass/block-arg.rs +++ b/src/test/run-pass/block-arg.rs @@ -10,7 +10,7 @@ // Check usage and precedence of block arguments in expressions: pub fn main() { - let v = vec!(-1.0f64, 0.0, 1.0, 2.0, 3.0); + let v = vec![-1.0f64, 0.0, 1.0, 2.0, 3.0]; // Statement form does not require parentheses: for i in &v { diff --git a/src/test/run-pass/borrow-by-val-method-receiver.rs b/src/test/run-pass/borrow-by-val-method-receiver.rs index 052b605393..44f4a54610 100644 --- a/src/test/run-pass/borrow-by-val-method-receiver.rs +++ b/src/test/run-pass/borrow-by-val-method-receiver.rs @@ -17,6 +17,6 @@ impl<'a> Foo for &'a [isize] { } pub fn main() { - let items = vec!( 3, 5, 1, 2, 4 ); + let items = vec![ 3, 5, 1, 2, 4 ]; items.foo(); } diff --git a/src/test/run-pass/borrowck/borrowck-binding-mutbl.rs b/src/test/run-pass/borrowck/borrowck-binding-mutbl.rs index 187063968f..b6c2a3a61e 100644 --- a/src/test/run-pass/borrowck/borrowck-binding-mutbl.rs +++ b/src/test/run-pass/borrowck/borrowck-binding-mutbl.rs @@ -14,7 +14,7 @@ fn impure(_v: &[isize]) { } pub fn main() { - let mut x = F {f: vec!(3)}; + let mut x = F {f: vec![3]}; match x { F {f: ref mut v} => { diff --git a/src/test/run-pass/borrowck/borrowck-mut-vec-as-imm-slice.rs b/src/test/run-pass/borrowck/borrowck-mut-vec-as-imm-slice.rs index d55517c65d..4699f37631 100644 --- a/src/test/run-pass/borrowck/borrowck-mut-vec-as-imm-slice.rs +++ b/src/test/run-pass/borrowck/borrowck-mut-vec-as-imm-slice.rs @@ -21,5 +21,5 @@ fn has_mut_vec(v: Vec ) -> isize { } pub fn main() { - assert_eq!(has_mut_vec(vec!(1, 2, 3)), 6); + assert_eq!(has_mut_vec(vec![1, 2, 3]), 6); } diff --git a/src/test/run-pass/borrowck/borrowck-pat-enum.rs b/src/test/run-pass/borrowck/borrowck-pat-enum.rs index b29cb63f6f..8de45e4205 100644 --- a/src/test/run-pass/borrowck/borrowck-pat-enum.rs +++ b/src/test/run-pass/borrowck/borrowck-pat-enum.rs @@ -8,7 +8,7 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -// ignore-pretty +// ignore-pretty issue #37199 fn match_ref(v: Option) -> isize { match v { diff --git a/src/test/run-pass/break.rs b/src/test/run-pass/break.rs index ea136e2dc4..9a32fbc103 100644 --- a/src/test/run-pass/break.rs +++ b/src/test/run-pass/break.rs @@ -26,7 +26,7 @@ pub fn main() { i += 1; if i % 2 == 0 { continue; } assert!((i % 2 != 0)); if i >= 10 { break; } } - let ys = vec!(1, 2, 3, 4, 5, 6); + let ys = vec![1, 2, 3, 4, 5, 6]; for x in &ys { if *x % 2 == 0 { continue; } assert!((*x % 2 != 0)); 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 5bbdec95b1..846b695c35 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 @@ -14,7 +14,7 @@ struct X { } trait Changer { - fn change(mut self) -> Self; + fn change(self) -> Self; } impl Changer for X { diff --git a/src/test/run-pass/byte-literals.rs b/src/test/run-pass/byte-literals.rs index 9f7b98a57f..ad779d26f9 100644 --- a/src/test/run-pass/byte-literals.rs +++ b/src/test/run-pass/byte-literals.rs @@ -57,7 +57,7 @@ pub fn main() { _ => panic!(), } - let buf = vec!(97u8, 98, 99, 100); + let buf = vec![97u8, 98, 99, 100]; assert_eq!(match &buf[0..3] { b"def" => 1, b"abc" => 2, diff --git a/src/test/run-pass/cci_no_inline_exe.rs b/src/test/run-pass/cci_no_inline_exe.rs index cc76ed530c..b105411c28 100644 --- a/src/test/run-pass/cci_no_inline_exe.rs +++ b/src/test/run-pass/cci_no_inline_exe.rs @@ -21,7 +21,7 @@ pub fn main() { // actually working. //let bt0 = sys::frame_address(); //println!("%?", bt0); - iter(vec!(1, 2, 3), |i| { + iter(vec![1, 2, 3], |i| { println!("{}", i); //let bt1 = sys::frame_address(); diff --git a/src/test/run-pass/cfg-in-crate-1.rs b/src/test/run-pass/cfg-in-crate-1.rs index 06f679b7fc..5dd6fa45bb 100644 --- a/src/test/run-pass/cfg-in-crate-1.rs +++ b/src/test/run-pass/cfg-in-crate-1.rs @@ -9,8 +9,6 @@ // except according to those terms. // compile-flags: --cfg bar -D warnings -// ignore-pretty - #![cfg(bar)] fn main() {} 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 4d247bde19..7d266181c9 100644 --- a/src/test/run-pass/class-poly-methods-cross-crate.rs +++ b/src/test/run-pass/class-poly-methods-cross-crate.rs @@ -14,12 +14,12 @@ extern crate cci_class_6; use cci_class_6::kitties::cat; pub fn main() { - let mut nyan : cat = cat::(52_usize, 99, vec!('p')); - let mut kitty = cat(1000_usize, 2, vec!("tabby".to_string())); + let mut nyan : cat = cat::(52_usize, 99, vec!['p']); + let mut kitty = cat(1000_usize, 2, vec!["tabby".to_string()]); assert_eq!(nyan.how_hungry, 99); assert_eq!(kitty.how_hungry, 2); - nyan.speak(vec!(1_usize,2_usize,3_usize)); + nyan.speak(vec![1_usize,2_usize,3_usize]); assert_eq!(nyan.meow_count(), 55_usize); - kitty.speak(vec!("meow".to_string(), "mew".to_string(), "purr".to_string(), "chirp".to_string())); + kitty.speak(vec!["meow".to_string(), "mew".to_string(), "purr".to_string(), "chirp".to_string()]); assert_eq!(kitty.meow_count(), 1004_usize); } diff --git a/src/test/run-pass/class-poly-methods.rs b/src/test/run-pass/class-poly-methods.rs index 2528ff5128..5da858e3c4 100644 --- a/src/test/run-pass/class-poly-methods.rs +++ b/src/test/run-pass/class-poly-methods.rs @@ -33,12 +33,12 @@ fn cat(in_x : usize, in_y : isize, in_info: Vec ) -> cat { } pub fn main() { - let mut nyan : cat = cat::(52, 99, vec!(9)); - let mut kitty = cat(1000, 2, vec!("tabby".to_string())); + let mut nyan : cat = cat::(52, 99, vec![9]); + let mut kitty = cat(1000, 2, vec!["tabby".to_string()]); assert_eq!(nyan.how_hungry, 99); assert_eq!(kitty.how_hungry, 2); - nyan.speak(vec!(1,2,3)); + nyan.speak(vec![1,2,3]); assert_eq!(nyan.meow_count(), 55); - kitty.speak(vec!("meow".to_string(), "mew".to_string(), "purr".to_string(), "chirp".to_string())); + kitty.speak(vec!["meow".to_string(), "mew".to_string(), "purr".to_string(), "chirp".to_string()]); assert_eq!(kitty.meow_count(), 1004); } 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 25d3eb3bbe..c401b529c3 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 @@ -41,7 +41,7 @@ fn do_it(x: &[usize]) -> Foo { panic!() } -fn get_bar(x: usize) -> Vec { vec!(x * 2) } +fn get_bar(x: usize) -> Vec { vec![x * 2] } pub fn fails() { let x = 2; 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 4e116ae146..e86f20694e 100644 --- a/src/test/run-pass/coerce-reborrow-imm-vec-rcvr.rs +++ b/src/test/run-pass/coerce-reborrow-imm-vec-rcvr.rs @@ -19,7 +19,7 @@ fn bip(v: &[usize]) -> Vec { } pub fn main() { - let mut the_vec = vec!(1, 2, 3, 100); + let mut the_vec = vec![1, 2, 3, 100]; assert_eq!(the_vec.clone(), bar(&mut the_vec)); assert_eq!(the_vec.clone(), bip(&the_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 ce0bc33905..ca4ee4a97d 100644 --- a/src/test/run-pass/coerce-reborrow-mut-vec-arg.rs +++ b/src/test/run-pass/coerce-reborrow-mut-vec-arg.rs @@ -21,7 +21,7 @@ fn bar(v: &mut [usize]) { } pub fn main() { - let mut the_vec = vec!(1, 2, 3, 100); + let mut the_vec = vec![1, 2, 3, 100]; bar(&mut the_vec); assert_eq!(the_vec, [100, 3, 2, 1]); } 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 066b33e007..f35735adbc 100644 --- a/src/test/run-pass/coerce-reborrow-mut-vec-rcvr.rs +++ b/src/test/run-pass/coerce-reborrow-mut-vec-rcvr.rs @@ -17,7 +17,7 @@ fn bar(v: &mut [usize]) { } pub fn main() { - let mut the_vec = vec!(1, 2, 3, 100); + let mut the_vec = vec![1, 2, 3, 100]; bar(&mut the_vec); assert_eq!(the_vec, [100, 3, 2, 1]); } diff --git a/src/test/run-pass/command-exec.rs b/src/test/run-pass/command-exec.rs index 130526e72b..5be9b97aac 100644 --- a/src/test/run-pass/command-exec.rs +++ b/src/test/run-pass/command-exec.rs @@ -9,9 +9,8 @@ // except according to those terms. // ignore-windows - this is a unix-specific test +// ignore-pretty issue #37199 // ignore-emscripten -// ignore-pretty - #![feature(process_exec)] use std::env; diff --git a/src/test/run-pass/const-err.rs b/src/test/run-pass/const-err.rs index 9f4ae1ad92..a1c9ff8a21 100644 --- a/src/test/run-pass/const-err.rs +++ b/src/test/run-pass/const-err.rs @@ -17,4 +17,8 @@ const X: *const u8 = b"" as _; fn main() { let _ = ((-1 as i8) << 8 - 1) as f32; let _ = 0u8 as char; + let _ = true > false; + let _ = true >= false; + let _ = true < false; + let _ = true >= false; } diff --git a/src/test/run-pass/core-run-destroy.rs b/src/test/run-pass/core-run-destroy.rs index ffcc1891c5..c5b5b6b24a 100644 --- a/src/test/run-pass/core-run-destroy.rs +++ b/src/test/run-pass/core-run-destroy.rs @@ -8,7 +8,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -// ignore-pretty // compile-flags:--test // ignore-emscripten diff --git a/src/test/run-pass/cstring-drop.rs b/src/test/run-pass/cstring-drop.rs deleted file mode 100644 index 960391bb8d..0000000000 --- a/src/test/run-pass/cstring-drop.rs +++ /dev/null @@ -1,49 +0,0 @@ -// Copyright 2016 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution and at -// http://rust-lang.org/COPYRIGHT. -// -// Licensed under the Apache License, Version 2.0 or the MIT license -// , at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - -// ignore-emscripten - -// Test that `CString::new("hello").unwrap().as_ptr()` pattern -// leads to failure. - -use std::env; -use std::ffi::{CString, CStr}; -use std::os::raw::c_char; -use std::process::{Command, Stdio}; - -fn main() { - let args: Vec = env::args().collect(); - if args.len() > 1 && args[1] == "child" { - // Repeat several times to be more confident that - // it is `Drop` for `CString` that does the cleanup, - // and not just some lucky UB. - let xs = vec![CString::new("Hello").unwrap(); 10]; - let ys = xs.iter().map(|s| s.as_ptr()).collect::>(); - drop(xs); - assert!(ys.into_iter().any(is_hello)); - return; - } - - let output = Command::new(&args[0]).arg("child").output().unwrap(); - assert!(!output.status.success()); -} - -fn is_hello(s: *const c_char) -> bool { - // `s` is a dangling pointer and reading it is technically - // undefined behavior. But we want to prevent the most diabolical - // kind of UB (apart from nasal demons): reading a value that was - // previously written. - // - // Segfaulting or reading an empty string is Ok, - // reading "Hello" is bad. - let s = unsafe { CStr::from_ptr(s) }; - let hello = CString::new("Hello").unwrap(); - s == hello.as_ref() -} diff --git a/src/test/run-pass/deprecated-macro_escape-inner.rs b/src/test/run-pass/deprecated-macro_escape-inner.rs index 7960a91bdc..1a2be7a719 100644 --- a/src/test/run-pass/deprecated-macro_escape-inner.rs +++ b/src/test/run-pass/deprecated-macro_escape-inner.rs @@ -8,8 +8,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -// ignore-pretty - mod foo { #![macro_escape] //~ WARNING macro_escape is a deprecated synonym for macro_use //~^ HELP consider an outer attribute diff --git a/src/test/run-pass/deprecated-macro_escape.rs b/src/test/run-pass/deprecated-macro_escape.rs index b03905e1a0..b9f756cc79 100644 --- a/src/test/run-pass/deprecated-macro_escape.rs +++ b/src/test/run-pass/deprecated-macro_escape.rs @@ -8,8 +8,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -// ignore-pretty - #[macro_escape] //~ WARNING macro_escape is a deprecated synonym for macro_use mod foo { } diff --git a/src/test/run-pass/deriving-cmp-generic-enum.rs b/src/test/run-pass/deriving-cmp-generic-enum.rs index b1cd1877a7..b2add21dcd 100644 --- a/src/test/run-pass/deriving-cmp-generic-enum.rs +++ b/src/test/run-pass/deriving-cmp-generic-enum.rs @@ -8,9 +8,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -// no-pretty-expanded FIXME #15189 - - #[derive(PartialEq, Eq, PartialOrd, Ord)] enum E { E0, diff --git a/src/test/run-pass/deriving-in-macro.rs b/src/test/run-pass/deriving-in-macro.rs index b23075e6d0..adc3e3efd7 100644 --- a/src/test/run-pass/deriving-in-macro.rs +++ b/src/test/run-pass/deriving-in-macro.rs @@ -19,6 +19,6 @@ macro_rules! define_vec { ) } -define_vec!(); +define_vec![]; pub fn main() {} diff --git a/src/test/run-pass/deriving-meta-empty-trait-list.rs b/src/test/run-pass/deriving-meta-empty-trait-list.rs index ff513325d5..ed8a50998d 100644 --- a/src/test/run-pass/deriving-meta-empty-trait-list.rs +++ b/src/test/run-pass/deriving-meta-empty-trait-list.rs @@ -1,5 +1,3 @@ -// ignore-pretty - // 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. diff --git a/src/test/run-pass/deriving-show.rs b/src/test/run-pass/deriving-show.rs index 1f30f3eced..e858ba8c82 100644 --- a/src/test/run-pass/deriving-show.rs +++ b/src/test/run-pass/deriving-show.rs @@ -24,6 +24,9 @@ enum Enum { StructVariant { x: isize, y : usize } } +#[derive(Debug)] +struct Pointers(*const Send, *mut Sync); + macro_rules! t { ($x:expr, $expected:expr) => { assert_eq!(format!("{:?}", $x), $expected.to_string()) diff --git a/src/test/run-pass/discriminant_value-wrapper.rs b/src/test/run-pass/discriminant_value-wrapper.rs new file mode 100644 index 0000000000..2dbda0be18 --- /dev/null +++ b/src/test/run-pass/discriminant_value-wrapper.rs @@ -0,0 +1,28 @@ +// Copyright 2016 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +#![feature(discriminant_value)] + +use std::mem; + +enum ADT { + First(u32, u32), + Second(u64) +} + +pub fn main() { + assert!(mem::discriminant(&ADT::First(0,0)) == mem::discriminant(&ADT::First(1,1))); + assert!(mem::discriminant(&ADT::Second(5)) == mem::discriminant(&ADT::Second(6))); + assert!(mem::discriminant(&ADT::First(2,2)) != mem::discriminant(&ADT::Second(2))); + + let _ = mem::discriminant(&10); + let _ = mem::discriminant(&"test"); +} + 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 cb3712dea3..53005ea529 100644 --- a/src/test/run-pass/drop-with-type-ascription-2.rs +++ b/src/test/run-pass/drop-with-type-ascription-2.rs @@ -12,7 +12,7 @@ #![feature(collections)] fn main() { - let args = vec!("foobie", "asdf::asdf"); + let args = vec!["foobie", "asdf::asdf"]; let arr: Vec<&str> = args[1].split("::").collect(); assert_eq!(arr[0], "asdf"); assert_eq!(arr[0], "asdf"); diff --git a/src/test/run-pass/dropck-eyepatch-extern-crate.rs b/src/test/run-pass/dropck-eyepatch-extern-crate.rs new file mode 100644 index 0000000000..20f069f77e --- /dev/null +++ b/src/test/run-pass/dropck-eyepatch-extern-crate.rs @@ -0,0 +1,48 @@ +// Copyright 2016 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +// aux-build:dropck_eyepatch_extern_crate.rs + +extern crate dropck_eyepatch_extern_crate as other; + +use other::{Dt,Dr,Pt,Pr,St,Sr}; + +fn main() { + use std::cell::RefCell; + + struct CheckOnDrop(RefCell, &'static str); + impl Drop for CheckOnDrop { + fn drop(&mut self) { assert_eq!(*self.0.borrow(), self.1); } + } + + let c_long; + let (c, dt, dr, pt, pr, st, sr) + : (CheckOnDrop, Dt<_>, Dr<_>, Pt<_, _>, Pr<_>, St<_>, Sr<_>); + c_long = CheckOnDrop(RefCell::new("c_long".to_string()), + "c_long|pr|pt|dr|dt"); + c = CheckOnDrop(RefCell::new("c".to_string()), + "c"); + + // No error: sufficiently long-lived state can be referenced in dtors + dt = Dt("dt", &c_long.0); + dr = Dr("dr", &c_long.0); + + // No error: Drop impl asserts .1 (A and &'a _) are not accessed + pt = Pt("pt", &c.0, &c_long.0); + pr = Pr("pr", &c.0, &c_long.0); + + // No error: St and Sr have no destructor. + st = St("st", &c.0); + sr = Sr("sr", &c.0); + + println!("{:?}", (dt.0, dr.0, pt.0, pr.0, st.0, sr.0)); + assert_eq!(*c_long.0.borrow(), "c_long"); + assert_eq!(*c.0.borrow(), "c"); +} diff --git a/src/test/run-pass/dropck-eyepatch-reorder.rs b/src/test/run-pass/dropck-eyepatch-reorder.rs new file mode 100644 index 0000000000..bbf8bb8c35 --- /dev/null +++ b/src/test/run-pass/dropck-eyepatch-reorder.rs @@ -0,0 +1,89 @@ +// Copyright 2016 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +#![feature(generic_param_attrs)] +#![feature(dropck_eyepatch)] + +// The point of this test is to test uses of `#[may_dangle]` attribute +// where the formal declaration order (in the impl generics) does not +// match the actual usage order (in the type instantiation). +// +// See also dropck-eyepatch.rs for more information about the general +// structure of the test. + +trait Foo { fn foo(&self, _: &str); } + +struct Dt(&'static str, A); +struct Dr<'a, B:'a+Foo>(&'static str, &'a B); +struct Pt(&'static str, A, B); +struct Pr<'a, 'b, B:'a+'b+Foo>(&'static str, &'a B, &'b B); +struct St(&'static str, A); +struct Sr<'a, B:'a+Foo>(&'static str, &'a B); + +impl Drop for Dt { + fn drop(&mut self) { println!("drop {}", self.0); self.1.foo(self.0); } +} +impl<'a, B: Foo> Drop for Dr<'a, B> { + fn drop(&mut self) { println!("drop {}", self.0); self.1.foo(self.0); } +} +unsafe impl Drop for Pt { + // (unsafe to access self.1 due to #[may_dangle] on A) + fn drop(&mut self) { println!("drop {}", self.0); self.2.foo(self.0); } +} +unsafe impl<'b, #[may_dangle] 'a, B: Foo> Drop for Pr<'a, 'b, B> { + // (unsafe to access self.1 due to #[may_dangle] on 'a) + fn drop(&mut self) { println!("drop {}", self.0); self.2.foo(self.0); } +} + +fn main() { + use std::cell::RefCell; + + impl Foo for RefCell { + fn foo(&self, s: &str) { + let s2 = format!("{}|{}", *self.borrow(), s); + *self.borrow_mut() = s2; + } + } + + impl<'a, T:Foo> Foo for &'a T { + fn foo(&self, s: &str) { + (*self).foo(s); + } + } + + struct CheckOnDrop(RefCell, &'static str); + impl Drop for CheckOnDrop { + fn drop(&mut self) { assert_eq!(*self.0.borrow(), self.1); } + } + + let c_long; + let (c, dt, dr, pt, pr, st, sr) + : (CheckOnDrop, Dt<_>, Dr<_>, Pt<_, _>, Pr<_>, St<_>, Sr<_>); + c_long = CheckOnDrop(RefCell::new("c_long".to_string()), + "c_long|pr|pt|dr|dt"); + c = CheckOnDrop(RefCell::new("c".to_string()), + "c"); + + // No error: sufficiently long-lived state can be referenced in dtors + dt = Dt("dt", &c_long.0); + dr = Dr("dr", &c_long.0); + + // No error: Drop impl asserts .1 (A and &'a _) are not accessed + pt = Pt("pt", &c.0, &c_long.0); + pr = Pr("pr", &c.0, &c_long.0); + + // No error: St and Sr have no destructor. + st = St("st", &c.0); + sr = Sr("sr", &c.0); + + println!("{:?}", (dt.0, dr.0, pt.0, pr.0, st.0, sr.0)); + assert_eq!(*c_long.0.borrow(), "c_long"); + assert_eq!(*c.0.borrow(), "c"); +} diff --git a/src/test/run-pass/dropck-eyepatch.rs b/src/test/run-pass/dropck-eyepatch.rs new file mode 100644 index 0000000000..4a09ba05df --- /dev/null +++ b/src/test/run-pass/dropck-eyepatch.rs @@ -0,0 +1,112 @@ +// Copyright 2016 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +#![feature(generic_param_attrs)] +#![feature(dropck_eyepatch)] + +// The point of this test is to illustrate that the `#[may_dangle]` +// attribute specifically allows, in the context of a type +// implementing `Drop`, a generic parameter to be instantiated with a +// lifetime that does not strictly outlive the owning type itself. +// +// Here we test that a model use of `#[may_dangle]` will compile and run. +// +// The illustration is made concrete by comparison with two variations +// on the type with `#[may_dangle]`: +// +// 1. an analogous type that does not implement `Drop` (and thus +// should exhibit maximal flexibility with respect to dropck), and +// +// 2. an analogous type that does not use `#[may_dangle]` (and thus +// should exhibit the standard limitations imposed by dropck. +// +// The types in this file follow a pattern, {D,P,S}{t,r}, where: +// +// - D means "I implement Drop" +// +// - P means "I implement Drop but guarantee my (first) parameter is +// pure, i.e. not accessed from the destructor"; no other parameters +// are pure. +// +// - S means "I do not implement Drop" +// +// - t suffix is used when the first generic is a type +// +// - r suffix is used when the first generic is a lifetime. + +trait Foo { fn foo(&self, _: &str); } + +struct Dt(&'static str, A); +struct Dr<'a, B:'a+Foo>(&'static str, &'a B); +struct Pt(&'static str, A, B); +struct Pr<'a, 'b, B:'a+'b+Foo>(&'static str, &'a B, &'b B); +struct St(&'static str, A); +struct Sr<'a, B:'a+Foo>(&'static str, &'a B); + +impl Drop for Dt { + fn drop(&mut self) { println!("drop {}", self.0); self.1.foo(self.0); } +} +impl<'a, B: Foo> Drop for Dr<'a, B> { + fn drop(&mut self) { println!("drop {}", self.0); self.1.foo(self.0); } +} +unsafe impl<#[may_dangle] A, B: Foo> Drop for Pt { + // (unsafe to access self.1 due to #[may_dangle] on A) + fn drop(&mut self) { println!("drop {}", self.0); self.2.foo(self.0); } +} +unsafe impl<#[may_dangle] 'a, 'b, B: Foo> Drop for Pr<'a, 'b, B> { + // (unsafe to access self.1 due to #[may_dangle] on 'a) + fn drop(&mut self) { println!("drop {}", self.0); self.2.foo(self.0); } +} + +fn main() { + use std::cell::RefCell; + + impl Foo for RefCell { + fn foo(&self, s: &str) { + let s2 = format!("{}|{}", *self.borrow(), s); + *self.borrow_mut() = s2; + } + } + + impl<'a, T:Foo> Foo for &'a T { + fn foo(&self, s: &str) { + (*self).foo(s); + } + } + + struct CheckOnDrop(RefCell, &'static str); + impl Drop for CheckOnDrop { + fn drop(&mut self) { assert_eq!(*self.0.borrow(), self.1); } + } + + let c_long; + let (c, dt, dr, pt, pr, st, sr) + : (CheckOnDrop, Dt<_>, Dr<_>, Pt<_, _>, Pr<_>, St<_>, Sr<_>); + c_long = CheckOnDrop(RefCell::new("c_long".to_string()), + "c_long|pr|pt|dr|dt"); + c = CheckOnDrop(RefCell::new("c".to_string()), + "c"); + + // No error: sufficiently long-lived state can be referenced in dtors + dt = Dt("dt", &c_long.0); + dr = Dr("dr", &c_long.0); + + // No error: Drop impl asserts .1 (A and &'a _) are not accessed + pt = Pt("pt", &c.0, &c_long.0); + pr = Pr("pr", &c.0, &c_long.0); + + // No error: St and Sr have no destructor. + st = St("st", &c.0); + sr = Sr("sr", &c.0); + + println!("{:?}", (dt.0, dr.0, pt.0, pr.0, st.0, sr.0)); + assert_eq!(*c_long.0.borrow(), "c_long"); + assert_eq!(*c.0.borrow(), "c"); +} diff --git a/src/test/run-pass/enum-size-variance.rs b/src/test/run-pass/enum-size-variance.rs index 21996c5fab..26deb0ed72 100644 --- a/src/test/run-pass/enum-size-variance.rs +++ b/src/test/run-pass/enum-size-variance.rs @@ -8,8 +8,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. // -// ignore-pretty - #![warn(variant_size_differences)] #![allow(dead_code)] diff --git a/src/test/run-pass/expr-fn.rs b/src/test/run-pass/expr-fn.rs index aeca388d31..cc9a2e60de 100644 --- a/src/test/run-pass/expr-fn.rs +++ b/src/test/run-pass/expr-fn.rs @@ -16,7 +16,7 @@ fn test_int() { } fn test_vec() { - fn f() -> Vec { vec!(10, 11) } + fn f() -> Vec { vec![10, 11] } let vect = f(); assert_eq!(vect[1], 11); } diff --git a/src/test/run-pass/expr-match-panic.rs b/src/test/run-pass/expr-match-panic.rs index 89dc7b09c7..1a6466048d 100644 --- a/src/test/run-pass/expr-match-panic.rs +++ b/src/test/run-pass/expr-match-panic.rs @@ -16,7 +16,7 @@ fn test_simple() { } fn test_box() { - let r = match true { true => { vec!(10) } false => { panic!() } }; + let r = match true { true => { vec![10] } false => { panic!() } }; assert_eq!(r[0], 10); } diff --git a/src/test/run-pass/extern-methods.rs b/src/test/run-pass/extern-methods.rs index 421b19f286..2587a97863 100644 --- a/src/test/run-pass/extern-methods.rs +++ b/src/test/run-pass/extern-methods.rs @@ -8,6 +8,9 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. +// ignore-arm +// ignore-aarch64 + trait A { extern "fastcall" fn test1(i: i32); extern fn test2(i: i32); diff --git a/src/test/run-pass/extern-pass-empty.rs b/src/test/run-pass/extern-pass-empty.rs index 21948d2e5a..801a3c40ab 100644 --- a/src/test/run-pass/extern-pass-empty.rs +++ b/src/test/run-pass/extern-pass-empty.rs @@ -12,6 +12,7 @@ // pretty-expanded FIXME #23616 // ignore-msvc +// ignore-emscripten struct TwoU8s { one: u8, diff --git a/src/test/run-pass/extern-vectorcall.rs b/src/test/run-pass/extern-vectorcall.rs index e8a9f92a93..90c3459036 100644 --- a/src/test/run-pass/extern-vectorcall.rs +++ b/src/test/run-pass/extern-vectorcall.rs @@ -8,6 +8,9 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. +// ignore-arm +// ignore-aarch64 + #![feature(abi_vectorcall)] trait A { diff --git a/src/test/run-pass/for-destruct.rs b/src/test/run-pass/for-destruct.rs index 963d34a2d2..ba78ff4d53 100644 --- a/src/test/run-pass/for-destruct.rs +++ b/src/test/run-pass/for-destruct.rs @@ -12,7 +12,7 @@ struct Pair { x: isize, y: isize } pub fn main() { - for elt in &(vec!(Pair {x: 10, y: 20}, Pair {x: 30, y: 0})) { + for elt in &(vec![Pair {x: 10, y: 20}, Pair {x: 30, y: 0}]) { assert_eq!(elt.x + elt.y, 30); } } diff --git a/src/test/run-pass/foreach-nested.rs b/src/test/run-pass/foreach-nested.rs index 60068185f5..2c4d0cc764 100644 --- a/src/test/run-pass/foreach-nested.rs +++ b/src/test/run-pass/foreach-nested.rs @@ -13,7 +13,7 @@ fn two(mut it: F) where F: FnMut(isize) { it(0); it(1); } pub fn main() { - let mut a: Vec = vec!(-1, -1, -1, -1); + let mut a: Vec = vec![-1, -1, -1, -1]; let mut p: isize = 0; two(|i| { two(|j| { a[p as usize] = 10 * i + j; p += 1; }) diff --git a/src/test/run-pass/format-no-std.rs b/src/test/run-pass/format-no-std.rs index 62d54da56b..1b9b4ab32c 100644 --- a/src/test/run-pass/format-no-std.rs +++ b/src/test/run-pass/format-no-std.rs @@ -8,6 +8,8 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. +// ignore-emscripten missing rust_begin_unwind + #![feature(lang_items, start, collections)] #![no_std] diff --git a/src/test/run-pass/generic-ivec-leak.rs b/src/test/run-pass/generic-ivec-leak.rs index eb0546063f..d439c62380 100644 --- a/src/test/run-pass/generic-ivec-leak.rs +++ b/src/test/run-pass/generic-ivec-leak.rs @@ -10,4 +10,4 @@ enum wrapper { wrapped(T), } -pub fn main() { let _w = wrapper::wrapped(vec!(1, 2, 3, 4, 5)); } +pub fn main() { let _w = wrapper::wrapped(vec![1, 2, 3, 4, 5]); } diff --git a/src/test/run-pass/generic-static-methods.rs b/src/test/run-pass/generic-static-methods.rs index 7a496ebf8c..ad501ec7e9 100644 --- a/src/test/run-pass/generic-static-methods.rs +++ b/src/test/run-pass/generic-static-methods.rs @@ -25,5 +25,5 @@ impl vec_utils for Vec { } pub fn main() { - assert_eq!(vec_utils::map_(&vec!(1,2,3), |&x| x+1), [2,3,4]); + assert_eq!(vec_utils::map_(&vec![1,2,3], |&x| x+1), [2,3,4]); } diff --git a/src/test/run-pass/getopts_ref.rs b/src/test/run-pass/getopts_ref.rs index c9595d09e2..90726c21fa 100644 --- a/src/test/run-pass/getopts_ref.rs +++ b/src/test/run-pass/getopts_ref.rs @@ -17,7 +17,7 @@ use getopts::{optopt, getopts}; pub fn main() { let args = Vec::new(); - let opts = vec!(optopt("b", "", "something", "SMTHNG")); + let opts = vec![optopt("b", "", "something", "SMTHNG")]; match getopts(&args, &opts) { Ok(ref m) => diff --git a/src/test/run-pass/hashmap-memory.rs b/src/test/run-pass/hashmap-memory.rs index 8efc4cb1b1..2306fa9afa 100644 --- a/src/test/run-pass/hashmap-memory.rs +++ b/src/test/run-pass/hashmap-memory.rs @@ -99,5 +99,5 @@ mod map_reduce { pub fn main() { map_reduce::map_reduce( - vec!("../src/test/run-pass/hashmap-memory.rs".to_string())); + vec!["../src/test/run-pass/hashmap-memory.rs".to_string()]); } diff --git a/src/test/run-pass/html-literals.rs b/src/test/run-pass/html-literals.rs index a9cfe7a380..1e1fde4d1e 100644 --- a/src/test/run-pass/html-literals.rs +++ b/src/test/run-pass/html-literals.rs @@ -40,7 +40,7 @@ macro_rules! parse_node { parse_node!( [$(: $tags ($(:$tag_nodes),*))*]; [$(:$head_nodes,)* :tag(stringify!($head).to_string(), - vec!($($nodes),*))]; + vec![$($nodes),*])]; $($rest)* ) ); diff --git a/src/test/run-pass/hygiene.rs b/src/test/run-pass/hygiene.rs index d72386190e..91648ee579 100644 --- a/src/test/run-pass/hygiene.rs +++ b/src/test/run-pass/hygiene.rs @@ -22,23 +22,23 @@ fn f() { fn g() { let x = 0; - macro_rules! m { ($x:ident) => { - macro_rules! m2 { () => { ($x, x) } } + macro_rules! m { ($m1:ident, $m2:ident, $x:ident) => { + macro_rules! $m1 { () => { ($x, x) } } let x = 1; - macro_rules! m3 { () => { ($x, x) } } + macro_rules! $m2 { () => { ($x, x) } } } } let x = 2; - m!(x); + m!(m2, m3, x); let x = 3; assert_eq!(m2!(), (2, 0)); assert_eq!(m3!(), (2, 1)); let x = 4; - m!(x); - assert_eq!(m2!(), (4, 0)); - assert_eq!(m3!(), (4, 1)); + m!(m4, m5, x); + assert_eq!(m4!(), (4, 0)); + assert_eq!(m5!(), (4, 1)); } mod foo { diff --git a/src/test/run-pass/hygienic-labels-in-let.rs b/src/test/run-pass/hygienic-labels-in-let.rs index 5b45f1e0d3..2aa5f59cda 100644 --- a/src/test/run-pass/hygienic-labels-in-let.rs +++ b/src/test/run-pass/hygienic-labels-in-let.rs @@ -8,8 +8,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -// 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. diff --git a/src/test/run-pass/ifmt.rs b/src/test/run-pass/ifmt.rs index 0ebe1ca07c..2a7a593d26 100644 --- a/src/test/run-pass/ifmt.rs +++ b/src/test/run-pass/ifmt.rs @@ -8,8 +8,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -// no-pretty-expanded unnecessary unsafe block generated - #![deny(warnings)] #![allow(unused_must_use)] #![allow(unused_features)] @@ -239,7 +237,7 @@ fn test_write() { // can do with them just yet (to test the output) fn test_print() { print!("hi"); - print!("{:?}", vec!(0u8)); + print!("{:?}", vec![0u8]); println!("hello"); println!("this is a {}", "test"); println!("{foo}", foo="bar"); diff --git a/src/test/run-pass/import-glob-crate.rs b/src/test/run-pass/import-glob-crate.rs index b2a9b08b01..fec46c7e1f 100644 --- a/src/test/run-pass/import-glob-crate.rs +++ b/src/test/run-pass/import-glob-crate.rs @@ -8,9 +8,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. - -#![allow(dead_assignment)] - use std::mem::*; pub fn main() { @@ -20,3 +17,12 @@ pub fn main() { assert_eq!(x, 2); assert_eq!(y, 1); } + +#[allow(unused)] +fn f() { + mod foo { pub use *; } + mod bar { pub use ::*; } + + foo::main(); + bar::main(); +} diff --git a/src/test/run-pass/imports.rs b/src/test/run-pass/imports.rs index 9851dfe026..195b99c978 100644 --- a/src/test/run-pass/imports.rs +++ b/src/test/run-pass/imports.rs @@ -8,8 +8,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -// ignore-pretty : (#23623) problems when ending with // comments - #![feature(item_like_imports)] #![allow(unused)] diff --git a/src/test/run-pass/issue-11709.rs b/src/test/run-pass/issue-11709.rs index cfff7eb339..88d74a6581 100644 --- a/src/test/run-pass/issue-11709.rs +++ b/src/test/run-pass/issue-11709.rs @@ -8,7 +8,7 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -// ignore-pretty +// ignore-pretty issue #37199 // Don't panic on blocks without results // There are several tests in this run-pass that raised diff --git a/src/test/run-pass/issue-13204.rs b/src/test/run-pass/issue-13204.rs index 36f606e5d7..13e8fe0e96 100644 --- a/src/test/run-pass/issue-13204.rs +++ b/src/test/run-pass/issue-13204.rs @@ -28,6 +28,6 @@ impl Foo for Baz { fn main() { let x = Baz; - let y = vec!((), (), ()); + let y = vec![(), (), ()]; assert_eq!(x.bar(y.iter()), 3); } diff --git a/src/test/run-pass/issue-14936.rs b/src/test/run-pass/issue-14936.rs index 428d4e4dbb..8a628b73c0 100644 --- a/src/test/run-pass/issue-14936.rs +++ b/src/test/run-pass/issue-14936.rs @@ -24,7 +24,7 @@ macro_rules! demo { let mut x: isize = 0; let y: isize = 1; - let mut history: History = vec!(); + let mut history: History = vec![]; unsafe { asm!("mov ($1), $0" : $output_constraint (*wrap(&mut x, "out", &mut history)) diff --git a/src/test/run-pass/issue-15080.rs b/src/test/run-pass/issue-15080.rs index cee0caeb46..14e0037884 100644 --- a/src/test/run-pass/issue-15080.rs +++ b/src/test/run-pass/issue-15080.rs @@ -14,7 +14,7 @@ fn main() { let mut x: &[_] = &[1, 2, 3, 4]; - let mut result = vec!(); + let mut result = vec![]; loop { x = match *x { [1, n, 3, ref rest..] => { diff --git a/src/test/run-pass/issue-15189.rs b/src/test/run-pass/issue-15189.rs index 24340ac3f1..54b96d6630 100644 --- a/src/test/run-pass/issue-15189.rs +++ b/src/test/run-pass/issue-15189.rs @@ -8,14 +8,12 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -// ignore-pretty - macro_rules! third { ($e:expr) => ({let x = 2; $e[x]}) } fn main() { - let x = vec!(10_usize,11_usize,12_usize,13_usize); + let x = vec![10_usize,11_usize,12_usize,13_usize]; let t = third!(x); assert_eq!(t,12_usize); } diff --git a/src/test/run-pass/issue-15734.rs b/src/test/run-pass/issue-15734.rs index 66b0aeeb98..daf14b4c2f 100644 --- a/src/test/run-pass/issue-15734.rs +++ b/src/test/run-pass/issue-15734.rs @@ -54,7 +54,7 @@ impl> Index for Row { } fn main() { - let m = Mat::new(vec!(1, 2, 3, 4, 5, 6), 3); + let m = Mat::new(vec![1, 2, 3, 4, 5, 6], 3); let r = m.row(1); assert_eq!(r.index(2), &6); diff --git a/src/test/run-pass/issue-16492.rs b/src/test/run-pass/issue-16492.rs index 975557726c..177550a0dd 100644 --- a/src/test/run-pass/issue-16492.rs +++ b/src/test/run-pass/issue-16492.rs @@ -8,8 +8,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -// ignore-pretty - use std::rc::Rc; use std::cell::Cell; diff --git a/src/test/run-pass/issue-16597-empty.rs b/src/test/run-pass/issue-16597-empty.rs index a6a1c5f16b..c51e33c010 100644 --- a/src/test/run-pass/issue-16597-empty.rs +++ b/src/test/run-pass/issue-16597-empty.rs @@ -9,7 +9,6 @@ // except according to those terms. // compile-flags:--test -// no-pretty-expanded // This verifies that the test generation doesn't crash when we have // no tests - for more information, see PR #16892. diff --git a/src/test/run-pass/issue-16597.rs b/src/test/run-pass/issue-16597.rs index 7f0a341f14..583d8d4623 100644 --- a/src/test/run-pass/issue-16597.rs +++ b/src/test/run-pass/issue-16597.rs @@ -9,7 +9,6 @@ // except according to those terms. // compile-flags:--test -// ignore-pretty turns out the pretty-printer doesn't handle gensym'd things... mod tests { use super::*; diff --git a/src/test/run-pass/issue-16668.rs b/src/test/run-pass/issue-16668.rs index 0fd9965028..18861feb19 100644 --- a/src/test/run-pass/issue-16668.rs +++ b/src/test/run-pass/issue-16668.rs @@ -8,8 +8,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -// ignore-pretty - #![allow(unknown_features)] struct Parser<'a, I, O> { diff --git a/src/test/run-pass/issue-18060.rs b/src/test/run-pass/issue-18060.rs new file mode 100644 index 0000000000..d6c9a92ca0 --- /dev/null +++ b/src/test/run-pass/issue-18060.rs @@ -0,0 +1,17 @@ +// Copyright 2016 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +// Regression test for #18060: match arms were matching in the wrong order. + +fn main() { + assert_eq!(2, match (1, 3) { (0, 2...5) => 1, (1, 3) => 2, (_, 2...5) => 3, (_, _) => 4 }); + assert_eq!(2, match (1, 3) { (1, 3) => 2, (_, 2...5) => 3, (_, _) => 4 }); + assert_eq!(2, match (1, 7) { (0, 2...5) => 1, (1, 7) => 2, (_, 2...5) => 3, (_, _) => 4 }); +} diff --git a/src/test/run-pass/issue-18088.rs b/src/test/run-pass/issue-18088.rs new file mode 100644 index 0000000000..a45256387d --- /dev/null +++ b/src/test/run-pass/issue-18088.rs @@ -0,0 +1,17 @@ +// Copyright 2016 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + + +pub trait Indexable: std::ops::Index { + fn index2(&self, i: usize) -> &T { + &self[i] + } +} +fn main() {} diff --git a/src/test/run-pass/issue-18464.rs b/src/test/run-pass/issue-18464.rs index 70217868a5..dff86bc1b4 100644 --- a/src/test/run-pass/issue-18464.rs +++ b/src/test/run-pass/issue-18464.rs @@ -8,8 +8,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -// ignore-pretty - #![deny(dead_code)] const LOW_RANGE: char = '0'; diff --git a/src/test/run-pass/issue-18937-1.rs b/src/test/run-pass/issue-18937-1.rs new file mode 100644 index 0000000000..7a24d087b4 --- /dev/null +++ b/src/test/run-pass/issue-18937-1.rs @@ -0,0 +1,30 @@ +// Copyright 2016 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 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 type-check this example. In particular, +// knowing that `T: 'a` allows us to deduce that `[U]: 'a` (because +// when `T=[U]` it implies that `U: 'a`). +// +// Regr. test for live code we found in the wild when fixing #18937. + +pub trait Leak { + fn leak<'a>(self) -> &'a T where T: 'a; +} + +impl Leak<[U]> for Vec { + fn leak<'a>(mut self) -> &'a [U] where [U]: 'a { + let r: *mut [U] = &mut self[..]; + std::mem::forget(self); + unsafe { &mut *r } + } +} +fn main() { + println!("Hello, world!"); +} diff --git a/src/test/run-pass/issue-20427.rs b/src/test/run-pass/issue-20427.rs index dd3d952224..985ca06735 100644 --- a/src/test/run-pass/issue-20427.rs +++ b/src/test/run-pass/issue-20427.rs @@ -9,7 +9,7 @@ // except according to those terms. // aux-build:i8.rs -// ignore-pretty (#23623) +// ignore-pretty issue #37201 extern crate i8; use std::string as i16; diff --git a/src/test/run-pass/issue-20823.rs b/src/test/run-pass/issue-20823.rs index c297998b64..4d31d0cedb 100644 --- a/src/test/run-pass/issue-20823.rs +++ b/src/test/run-pass/issue-20823.rs @@ -9,7 +9,6 @@ // except according to those terms. // compile-flags: --test -// no-pretty-expanded #![deny(unstable)] diff --git a/src/test/run-pass/issue-22546.rs b/src/test/run-pass/issue-22546.rs index b3cb8a7821..8516d344e1 100644 --- a/src/test/run-pass/issue-22546.rs +++ b/src/test/run-pass/issue-22546.rs @@ -51,4 +51,10 @@ fn main() { if let None:: = Some(8) { panic!(); } + if let None:: { .. } = Some(8) { + panic!(); + } + if let Option::None:: { .. } = Some(8) { + panic!(); + } } diff --git a/src/test/run-pass/issue-22992.rs b/src/test/run-pass/issue-22992.rs index ca8f804482..dc612fc0bc 100644 --- a/src/test/run-pass/issue-22992.rs +++ b/src/test/run-pass/issue-22992.rs @@ -8,7 +8,7 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -// ignore-pretty +// ignore-pretty issue #37201 struct X { val: i32 } impl std::ops::Deref for X { 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 index fb84e7bae5..9d0612f2a8 100644 --- a/src/test/run-pass/issue-23338-ensure-param-drop-order.rs +++ b/src/test/run-pass/issue-23338-ensure-param-drop-order.rs @@ -8,7 +8,7 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -// ignore-pretty : (#23623) problems when ending with // comments +// ignore-pretty issue #37201 // This test is ensuring that parameters are indeed dropped after // temporaries in a fn body. diff --git a/src/test/run-pass/issue-2631-b.rs b/src/test/run-pass/issue-2631-b.rs index 365b594c99..913b07613e 100644 --- a/src/test/run-pass/issue-2631-b.rs +++ b/src/test/run-pass/issue-2631-b.rs @@ -19,7 +19,7 @@ use std::collections::HashMap; use std::rc::Rc; pub fn main() { - let v = vec!(Rc::new("hi".to_string())); + let v = vec![Rc::new("hi".to_string())]; let mut m: req::header_map = HashMap::new(); m.insert("METHOD".to_string(), Rc::new(RefCell::new(v))); request::(&m); diff --git a/src/test/run-pass/issue-26873-multifile.rs b/src/test/run-pass/issue-26873-multifile.rs index aa525ae951..51bf4bfe0e 100644 --- a/src/test/run-pass/issue-26873-multifile.rs +++ b/src/test/run-pass/issue-26873-multifile.rs @@ -7,10 +7,9 @@ // , at your // option. This file may not be copied, modified, or distributed // except according to those terms. -// -// ignore-pretty + +// ignore-pretty issue #37195 mod issue_26873_multifile; fn main() {} - diff --git a/src/test/run-pass/issue-2723-b.rs b/src/test/run-pass/issue-2723-b.rs index bab7b0d24d..a6ba957a1b 100644 --- a/src/test/run-pass/issue-2723-b.rs +++ b/src/test/run-pass/issue-2723-b.rs @@ -15,6 +15,6 @@ use issue_2723_a::f; pub fn main() { unsafe { - f(vec!(2)); + f(vec![2]); } } diff --git a/src/test/run-pass/issue-27401-dropflag-reinit.rs b/src/test/run-pass/issue-27401-dropflag-reinit.rs index ab8f22e78b..37dc060d5d 100644 --- a/src/test/run-pass/issue-27401-dropflag-reinit.rs +++ b/src/test/run-pass/issue-27401-dropflag-reinit.rs @@ -8,7 +8,7 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -// ignore-pretty #27582 +// ignore-pretty issue #37201 // Check that when a `let`-binding occurs in a loop, its associated // drop-flag is reinitialized (to indicate "needs-drop" at the end of diff --git a/src/test/run-pass/issue-27639.rs b/src/test/run-pass/issue-27639.rs index 44c1eb86de..ce1abb163d 100644 --- a/src/test/run-pass/issue-27639.rs +++ b/src/test/run-pass/issue-27639.rs @@ -8,8 +8,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -// ignore-pretty - fn main() { const iter: i32 = 0; diff --git a/src/test/run-pass/issue-28839.rs b/src/test/run-pass/issue-28839.rs index a101229662..2ff4403a42 100644 --- a/src/test/run-pass/issue-28839.rs +++ b/src/test/run-pass/issue-28839.rs @@ -8,7 +8,7 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -// ignore-pretty : (#23623) problems with newlines before // comments +// ignore-pretty issue #37199 pub struct Foo; diff --git a/src/test/run-pass/issue-28936.rs b/src/test/run-pass/issue-28936.rs index 2a932cd775..992fbdce26 100644 --- a/src/test/run-pass/issue-28936.rs +++ b/src/test/run-pass/issue-28936.rs @@ -23,7 +23,7 @@ pub fn parse_stream, U, F>( where F: Fn(&mut StreamParser) -> U { panic!(); } pub fn thing(session: &mut Session) { - let mut stream = vec!(1, 2, 3).into_iter(); + let mut stream = vec![1, 2, 3].into_iter(); let _b = parse_stream(session, stream.by_ref(), diff --git a/src/test/run-pass/issue-29740.rs b/src/test/run-pass/issue-29740.rs index 75bcd431ec..eb7b740db6 100644 --- a/src/test/run-pass/issue-29740.rs +++ b/src/test/run-pass/issue-29740.rs @@ -11,8 +11,6 @@ // Regression test for #29740. Inefficient MIR matching algorithms // generated way too much code for this sort of case, leading to OOM. -// ignore-pretty - pub mod KeyboardEventConstants { pub const DOM_KEY_LOCATION_STANDARD: u32 = 0; pub const DOM_KEY_LOCATION_LEFT: u32 = 1; diff --git a/src/test/run-pass/issue-2989.rs b/src/test/run-pass/issue-2989.rs index 8b6eb12f10..a4342f3340 100644 --- a/src/test/run-pass/issue-2989.rs +++ b/src/test/run-pass/issue-2989.rs @@ -32,8 +32,8 @@ fn to_bools(bitv: Storage) -> Vec { struct Storage { storage: Vec } pub fn main() { - let bools = vec!(false, false, true, false, false, true, true, false); - let bools2 = to_bools(Storage{storage: vec!(0b01100100)}); + let bools = vec![false, false, true, false, false, true, true, false]; + let bools2 = to_bools(Storage{storage: vec![0b01100100]}); for i in 0..8 { println!("{} => {} vs {}", i, bools[i], bools2[i]); diff --git a/src/test/run-pass/issue-3389.rs b/src/test/run-pass/issue-3389.rs index 26558bdd30..70e3484a0c 100644 --- a/src/test/run-pass/issue-3389.rs +++ b/src/test/run-pass/issue-3389.rs @@ -25,8 +25,8 @@ pub fn main() { content: Vec::new(), children: Vec::new() }; - let v = vec!("123".to_string(), "abc".to_string()); - node.content = vec!("123".to_string(), "abc".to_string()); + let v = vec!["123".to_string(), "abc".to_string()]; + node.content = vec!["123".to_string(), "abc".to_string()]; print_str_vector(v); print_str_vector(node.content.clone()); diff --git a/src/test/run-pass/issue-34932.rs b/src/test/run-pass/issue-34932.rs index e83939e7ae..dca387dcc2 100644 --- a/src/test/run-pass/issue-34932.rs +++ b/src/test/run-pass/issue-34932.rs @@ -10,8 +10,6 @@ // compile-flags:--test // rustc-env:RUSTC_BOOTSTRAP_KEY= -// ignore-pretty : (#23623) problems when ending with // comments - #![cfg(any())] // This test should be configured away #![feature(rustc_attrs)] // Test that this is allowed on stable/beta #![feature(iter_arith_traits)] // Test that this is not unused diff --git a/src/test/run-pass/issue-36768.rs b/src/test/run-pass/issue-36768.rs new file mode 100644 index 0000000000..bb4d12919a --- /dev/null +++ b/src/test/run-pass/issue-36768.rs @@ -0,0 +1,18 @@ +// Copyright 2016 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +// compile-flags:--test +#![deny(private_in_public)] + +#[test] fn foo() {} +mod foo {} + +#[test] fn core() {} +extern crate core; diff --git a/src/test/run-pass/issue-36786-resolve-call.rs b/src/test/run-pass/issue-36786-resolve-call.rs new file mode 100644 index 0000000000..0d718c7ba4 --- /dev/null +++ b/src/test/run-pass/issue-36786-resolve-call.rs @@ -0,0 +1,17 @@ +// Copyright 2016 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +// Ensure that types that rely on obligations are autoderefed +// correctly + +fn main() { + let x : Vec> = vec![Box::new(|| ())]; + x[0]() +} diff --git a/src/test/run-pass/issue-36816.rs b/src/test/run-pass/issue-36816.rs new file mode 100644 index 0000000000..22f3a52b26 --- /dev/null +++ b/src/test/run-pass/issue-36816.rs @@ -0,0 +1,16 @@ +// Copyright 2016 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +macro_rules! m { () => { 1 } } +macro_rules! n { () => { 1 + m!() } } + +fn main() { + let _: [u32; n!()] = [0, 0]; +} diff --git a/src/test/run-pass/issue-36954.rs b/src/test/run-pass/issue-36954.rs new file mode 100644 index 0000000000..f8330ba99b --- /dev/null +++ b/src/test/run-pass/issue-36954.rs @@ -0,0 +1,17 @@ +// Copyright 2016 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +// aux-build:issue-36954.rs + +extern crate issue_36954 as lib; + +fn main() { + let _ = lib::FOO; +} diff --git a/src/test/run-pass/issue-37175.rs b/src/test/run-pass/issue-37175.rs new file mode 100644 index 0000000000..0d3613b573 --- /dev/null +++ b/src/test/run-pass/issue-37175.rs @@ -0,0 +1,14 @@ +// Copyright 2016 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +macro_rules! m { (<$t:ty>) => { stringify!($t) } } +fn main() { + println!("{}", m!(>)); +} diff --git a/src/test/run-pass/issue-37686.rs b/src/test/run-pass/issue-37686.rs new file mode 100644 index 0000000000..47881d4d53 --- /dev/null +++ b/src/test/run-pass/issue-37686.rs @@ -0,0 +1,16 @@ +// Copyright 2016 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +fn main() { + match (0, 0) { + (std::usize::MIN, std::usize::MAX) => {} + _ => {} + } +} diff --git a/src/test/run-pass/issue-38002.rs b/src/test/run-pass/issue-38002.rs new file mode 100644 index 0000000000..489d35e914 --- /dev/null +++ b/src/test/run-pass/issue-38002.rs @@ -0,0 +1,45 @@ +// Copyright 2016 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +// Check that constant ADTs are translated OK, part k of N. + +#![feature(slice_patterns)] + +enum Bar { + C +} + +enum Foo { + A {}, + B { + y: usize, + z: Bar + }, +} + +const LIST: [(usize, Foo); 2] = [ + (51, Foo::B { y: 42, z: Bar::C }), + (52, Foo::B { y: 45, z: Bar::C }), +]; + +pub fn main() { + match LIST { + [ + (51, Foo::B { y: 42, z: Bar::C }), + (52, Foo::B { y: 45, z: Bar::C }) + ] => {} + _ => { + // I would want to print the enum here, but if + // the discriminant is garbage this causes an + // `unreachable` and silent process exit. + panic!("trivial match failed") + } + } +} diff --git a/src/test/run-pass/issue-38033.rs b/src/test/run-pass/issue-38033.rs new file mode 100644 index 0000000000..50549dc8b2 --- /dev/null +++ b/src/test/run-pass/issue-38033.rs @@ -0,0 +1,88 @@ +// Copyright 2016 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +use std::marker; +use std::mem; + +fn main() { + let workers = (0..0).map(|_| result::()); + drop(join_all(workers).poll()); +} + +trait Future { + type Item; + type Error; + + fn poll(&mut self) -> Result; +} + +trait IntoFuture { + type Future: Future; + type Item; + type Error; + + fn into_future(self) -> Self::Future; +} + +impl IntoFuture for F { + type Future = F; + type Item = F::Item; + type Error = F::Error; + + fn into_future(self) -> F { + self + } +} + +struct FutureResult { + _inner: marker::PhantomData<(T, E)>, +} + +fn result() -> FutureResult { + loop {} +} + +impl Future for FutureResult { + type Item = T; + type Error = E; + + fn poll(&mut self) -> Result { + loop {} + } +} + +struct JoinAll + where I: IntoIterator, + I::Item: IntoFuture, +{ + elems: Vec<::Item>, +} + +fn join_all(_: I) -> JoinAll + where I: IntoIterator, + I::Item: IntoFuture, +{ + JoinAll { elems: vec![] } +} + +impl Future for JoinAll + where I: IntoIterator, + I::Item: IntoFuture, +{ + type Item = Vec<::Item>; + type Error = ::Error; + + fn poll(&mut self) -> Result { + let elems = mem::replace(&mut self.elems, Vec::new()); + Ok(elems.into_iter().map(|e| { + e + }).collect::>()) + } +} diff --git a/src/test/run-pass/issue-6153.rs b/src/test/run-pass/issue-6153.rs index 16e7060f4b..1b16418ac4 100644 --- a/src/test/run-pass/issue-6153.rs +++ b/src/test/run-pass/issue-6153.rs @@ -11,7 +11,7 @@ fn swap(f: F) -> Vec where F: FnOnce(Vec) -> Vec { - let x = vec!(1, 2, 3); + let x = vec![1, 2, 3]; f(x) } diff --git a/src/test/run-pass/issue-7911.rs b/src/test/run-pass/issue-7911.rs index 5324ddb49e..764d6fa791 100644 --- a/src/test/run-pass/issue-7911.rs +++ b/src/test/run-pass/issue-7911.rs @@ -8,8 +8,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -// ignore-pretty - // (Closes #7911) Test that we can use the same self expression // with different mutability in macro in two methods diff --git a/src/test/run-pass/issue-8460.rs b/src/test/run-pass/issue-8460.rs index f16057ccab..5148be5af8 100644 --- a/src/test/run-pass/issue-8460.rs +++ b/src/test/run-pass/issue-8460.rs @@ -9,8 +9,6 @@ // except according to those terms. // ignore-emscripten no threads support -// ignore-pretty : (#23623) problems when ending with // comments - #![feature(rustc_attrs, zero_one)] use std::num::Zero; diff --git a/src/test/run-pass/issue-9129.rs b/src/test/run-pass/issue-9129.rs index 99db47c172..c46e8494e7 100644 --- a/src/test/run-pass/issue-9129.rs +++ b/src/test/run-pass/issue-9129.rs @@ -8,7 +8,7 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -// ignore-pretty +// ignore-pretty unreported #![allow(unknown_features)] #![feature(box_syntax)] diff --git a/src/test/run-pass/iter-step-overflow-debug.rs b/src/test/run-pass/iter-step-overflow-debug.rs new file mode 100644 index 0000000000..5b9b58f028 --- /dev/null +++ b/src/test/run-pass/iter-step-overflow-debug.rs @@ -0,0 +1,29 @@ +// Copyright 2016 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +// compile-flags: -C debug_assertions=yes + +use std::panic; + +fn main() { + let r = panic::catch_unwind(|| { + let mut it = u8::max_value()..; + it.next().unwrap(); // 255 + it.next().unwrap(); + }); + assert!(r.is_err()); + + let r = panic::catch_unwind(|| { + let mut it = i8::max_value()..; + it.next().unwrap(); // 127 + it.next().unwrap(); + }); + assert!(r.is_err()); +} diff --git a/src/test/run-pass/iter-step-overflow-ndebug.rs b/src/test/run-pass/iter-step-overflow-ndebug.rs new file mode 100644 index 0000000000..8642f1643c --- /dev/null +++ b/src/test/run-pass/iter-step-overflow-ndebug.rs @@ -0,0 +1,21 @@ +// Copyright 2016 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +// compile-flags: -C debug_assertions=no + +fn main() { + let mut it = u8::max_value()..; + assert_eq!(it.next().unwrap(), 255); + assert_eq!(it.next().unwrap(), u8::min_value()); + + let mut it = i8::max_value()..; + assert_eq!(it.next().unwrap(), 127); + assert_eq!(it.next().unwrap(), i8::min_value()); +} diff --git a/src/test/run-pass/iter-zip.rs b/src/test/run-pass/iter-zip.rs new file mode 100644 index 0000000000..b0503bc204 --- /dev/null +++ b/src/test/run-pass/iter-zip.rs @@ -0,0 +1,112 @@ +// Copyright 2016 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +// Test that .zip() specialization preserves side effects +// in sideeffectful iterator adaptors. + +use std::cell::Cell; + +#[derive(Debug)] +struct CountClone(Cell); + +fn count_clone() -> CountClone { CountClone(Cell::new(0)) } + +impl PartialEq for CountClone { + fn eq(&self, rhs: &i32) -> bool { + self.0.get() == *rhs + } +} + +impl Clone for CountClone { + fn clone(&self) -> Self { + let ret = CountClone(self.0.clone()); + let n = self.0.get(); + self.0.set(n + 1); + ret + } +} + +fn test_zip_cloned_sideffectful() { + let xs = [count_clone(), count_clone(), count_clone(), count_clone()]; + let ys = [count_clone(), count_clone()]; + + for _ in xs.iter().cloned().zip(ys.iter().cloned()) { } + + assert_eq!(&xs, &[1, 1, 1, 0][..]); + assert_eq!(&ys, &[1, 1][..]); + + let xs = [count_clone(), count_clone()]; + let ys = [count_clone(), count_clone(), count_clone(), count_clone()]; + + for _ in xs.iter().cloned().zip(ys.iter().cloned()) { } + + assert_eq!(&xs, &[1, 1][..]); + assert_eq!(&ys, &[1, 1, 0, 0][..]); +} + +fn test_zip_map_sideffectful() { + let mut xs = [0; 6]; + let mut ys = [0; 4]; + + for _ in xs.iter_mut().map(|x| *x += 1).zip(ys.iter_mut().map(|y| *y += 1)) { } + + assert_eq!(&xs, &[1, 1, 1, 1, 1, 0]); + assert_eq!(&ys, &[1, 1, 1, 1]); + + let mut xs = [0; 4]; + let mut ys = [0; 6]; + + for _ in xs.iter_mut().map(|x| *x += 1).zip(ys.iter_mut().map(|y| *y += 1)) { } + + assert_eq!(&xs, &[1, 1, 1, 1]); + assert_eq!(&ys, &[1, 1, 1, 1, 0, 0]); +} + +fn test_zip_map_rev_sideffectful() { + let mut xs = [0; 6]; + let mut ys = [0; 4]; + + { + let mut it = xs.iter_mut().map(|x| *x += 1).zip(ys.iter_mut().map(|y| *y += 1)); + it.next_back(); + } + assert_eq!(&xs, &[0, 0, 0, 1, 1, 1]); + assert_eq!(&ys, &[0, 0, 0, 1]); + + let mut xs = [0; 6]; + let mut ys = [0; 4]; + + { + let mut it = xs.iter_mut().map(|x| *x += 1).zip(ys.iter_mut().map(|y| *y += 1)); + (&mut it).take(5).count(); + it.next_back(); + } + assert_eq!(&xs, &[1, 1, 1, 1, 1, 1]); + assert_eq!(&ys, &[1, 1, 1, 1]); +} + +fn test_zip_nested_sideffectful() { + let mut xs = [0; 6]; + let ys = [0; 4]; + + { + // test that it has the side effect nested inside enumerate + let it = xs.iter_mut().map(|x| *x = 1).enumerate().zip(&ys); + it.count(); + } + assert_eq!(&xs, &[1, 1, 1, 1, 1, 0]); +} + +fn main() { + test_zip_cloned_sideffectful(); + test_zip_map_sideffectful(); + test_zip_map_rev_sideffectful(); + test_zip_nested_sideffectful(); +} diff --git a/src/test/run-pass/ivec-pass-by-value.rs b/src/test/run-pass/ivec-pass-by-value.rs index 5b40105a97..e3b42e6064 100644 --- a/src/test/run-pass/ivec-pass-by-value.rs +++ b/src/test/run-pass/ivec-pass-by-value.rs @@ -9,4 +9,4 @@ // except according to those terms. fn f(_a: Vec ) { } -pub fn main() { f(vec!(1, 2, 3, 4, 5)); } +pub fn main() { f(vec![1, 2, 3, 4, 5]); } diff --git a/src/test/run-pass/ivec-tag.rs b/src/test/run-pass/ivec-tag.rs index b8238774bc..a511db8e93 100644 --- a/src/test/run-pass/ivec-tag.rs +++ b/src/test/run-pass/ivec-tag.rs @@ -17,8 +17,8 @@ use std::sync::mpsc::{channel, Sender}; fn producer(tx: &Sender>) { tx.send( - vec!(1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, - 13)).unwrap(); + vec![1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, + 13]).unwrap(); } pub fn main() { diff --git a/src/test/run-pass/lambda-infer-unresolved.rs b/src/test/run-pass/lambda-infer-unresolved.rs index fca700f6e4..5109c6fc77 100644 --- a/src/test/run-pass/lambda-infer-unresolved.rs +++ b/src/test/run-pass/lambda-infer-unresolved.rs @@ -15,7 +15,7 @@ struct Refs { refs: Vec , n: isize } pub fn main() { - let mut e = Refs{refs: vec!(), n: 0}; + let mut e = Refs{refs: vec![], n: 0}; let _f = || println!("{}", e.n); let x: &[isize] = &e.refs; assert_eq!(x.len(), 0); diff --git a/src/test/run-pass/lexer-crlf-line-endings-string-literal-doc-comment.rs b/src/test/run-pass/lexer-crlf-line-endings-string-literal-doc-comment.rs index 5c8db524cc..05f1f1bfea 100644 --- a/src/test/run-pass/lexer-crlf-line-endings-string-literal-doc-comment.rs +++ b/src/test/run-pass/lexer-crlf-line-endings-string-literal-doc-comment.rs @@ -15,7 +15,7 @@ // NB: this file needs CRLF line endings. The .gitattributes file in // this directory should enforce it. -// ignore-pretty +// ignore-pretty issue #37195 /// Doc comment that ends in CRLF pub fn foo() {} diff --git a/src/test/run-pass/linear-for-loop.rs b/src/test/run-pass/linear-for-loop.rs index ddb4e40aea..fc6d435b03 100644 --- a/src/test/run-pass/linear-for-loop.rs +++ b/src/test/run-pass/linear-for-loop.rs @@ -8,10 +8,8 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -// no-pretty-expanded FIXME #15189 - pub fn main() { - let x = vec!(1, 2, 3); + let x = vec![1, 2, 3]; let mut y = 0; for i in &x { println!("{}", *i); y += *i; } println!("{}", y); diff --git a/src/test/run-pass/log-poly.rs b/src/test/run-pass/log-poly.rs index d8a69177ca..b54b4692a4 100644 --- a/src/test/run-pass/log-poly.rs +++ b/src/test/run-pass/log-poly.rs @@ -17,5 +17,5 @@ pub fn main() { println!("{:?}", 1); println!("{:?}", 2.0f64); println!("{:?}", Numbers::Three); - println!("{:?}", vec!(4)); + println!("{:?}", vec![4]); } diff --git a/src/test/run-pass/loop-scope.rs b/src/test/run-pass/loop-scope.rs index 0c1e7916cd..6916bfb8c6 100644 --- a/src/test/run-pass/loop-scope.rs +++ b/src/test/run-pass/loop-scope.rs @@ -10,7 +10,7 @@ pub fn main() { - let x = vec!(10, 20, 30); + let x = vec![10, 20, 30]; let mut sum = 0; for x in &x { sum += *x; } assert_eq!(sum, 60); diff --git a/src/test/run-pass/macro-2.rs b/src/test/run-pass/macro-2.rs index 2cac922611..801d92b6dc 100644 --- a/src/test/run-pass/macro-2.rs +++ b/src/test/run-pass/macro-2.rs @@ -8,8 +8,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -// ignore-pretty - token trees can't pretty print - pub fn main() { macro_rules! mylambda_tt { diff --git a/src/test/run-pass/macro-attribute-expansion.rs b/src/test/run-pass/macro-attribute-expansion.rs index 60217139cd..c3de9f736f 100644 --- a/src/test/run-pass/macro-attribute-expansion.rs +++ b/src/test/run-pass/macro-attribute-expansion.rs @@ -8,8 +8,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -// ignore-pretty - token trees can't pretty print - macro_rules! descriptions { ($name:ident is $desc:expr) => { // Check that we will correctly expand attributes diff --git a/src/test/run-pass/macro-attributes.rs b/src/test/run-pass/macro-attributes.rs index 2752fc88b4..839fee3a2d 100644 --- a/src/test/run-pass/macro-attributes.rs +++ b/src/test/run-pass/macro-attributes.rs @@ -8,8 +8,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -// ignore-pretty - token trees can't pretty print - #![feature(custom_attribute)] macro_rules! compiles_fine { diff --git a/src/test/run-pass/macro-include-items.rs b/src/test/run-pass/macro-include-items.rs index 1e31c85afa..f8728ebb91 100644 --- a/src/test/run-pass/macro-include-items.rs +++ b/src/test/run-pass/macro-include-items.rs @@ -8,7 +8,7 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -// ignore-pretty +// ignore-pretty issue #37195 fn bar() {} diff --git a/src/test/run-pass/macro-meta-items.rs b/src/test/run-pass/macro-meta-items.rs index 605cade2b3..9c1e1fca34 100644 --- a/src/test/run-pass/macro-meta-items.rs +++ b/src/test/run-pass/macro-meta-items.rs @@ -8,7 +8,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -// ignore-pretty - token trees can't pretty print // compile-flags: --cfg foo macro_rules! compiles_fine { diff --git a/src/test/run-pass/macro-multiple-items.rs b/src/test/run-pass/macro-multiple-items.rs index f78f93e848..190bfc53a9 100644 --- a/src/test/run-pass/macro-multiple-items.rs +++ b/src/test/run-pass/macro-multiple-items.rs @@ -8,8 +8,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -// ignore-pretty - token trees can't pretty print - macro_rules! make_foo { () => ( struct Foo; diff --git a/src/test/run-pass/macro-stmt.rs b/src/test/run-pass/macro-stmt.rs index 0d8b86012d..027df9f93a 100644 --- a/src/test/run-pass/macro-stmt.rs +++ b/src/test/run-pass/macro-stmt.rs @@ -8,8 +8,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -// ignore-pretty - token trees can't pretty print - macro_rules! myfn { ( $f:ident, ( $( $x:ident ),* ), $body:block ) => ( fn $f( $( $x : isize),* ) -> isize $body diff --git a/src/test/run-pass/match-byte-array-patterns.rs b/src/test/run-pass/match-byte-array-patterns.rs new file mode 100644 index 0000000000..dbfe588fb0 --- /dev/null +++ b/src/test/run-pass/match-byte-array-patterns.rs @@ -0,0 +1,54 @@ +// Copyright 2016 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +#![feature(slice_patterns)] + +fn main() { + let buf = &[0u8; 4]; + match buf { + &[0, 1, 0, 0] => unimplemented!(), + b"true" => unimplemented!(), + _ => {} + } + + match buf { + b"true" => unimplemented!(), + &[0, 1, 0, 0] => unimplemented!(), + _ => {} + } + + match buf { + b"true" => unimplemented!(), + &[0, x, 0, 0] => assert_eq!(x, 0), + _ => unimplemented!(), + } + + let buf: &[u8] = buf; + + match buf { + &[0, 1, 0, 0] => unimplemented!(), + &[_] => unimplemented!(), + &[_, _, _, _, _, ..] => unimplemented!(), + b"true" => unimplemented!(), + _ => {} + } + + match buf { + b"true" => unimplemented!(), + &[0, 1, 0, 0] => unimplemented!(), + _ => {} + } + + match buf { + b"true" => unimplemented!(), + &[0, x, 0, 0] => assert_eq!(x, 0), + _ => unimplemented!(), + } +} diff --git a/src/test/run-pass/match-vec-rvalue.rs b/src/test/run-pass/match-vec-rvalue.rs index a10f9b1d7d..3d221927b9 100644 --- a/src/test/run-pass/match-vec-rvalue.rs +++ b/src/test/run-pass/match-vec-rvalue.rs @@ -13,7 +13,7 @@ pub fn main() { - match vec!(1, 2, 3) { + match vec![1, 2, 3] { x => { assert_eq!(x.len(), 3); assert_eq!(x[0], 1); diff --git a/src/test/run-pass/mir_raw_fat_ptr.rs b/src/test/run-pass/mir_raw_fat_ptr.rs index c9fd88f2fb..846318ec4f 100644 --- a/src/test/run-pass/mir_raw_fat_ptr.rs +++ b/src/test/run-pass/mir_raw_fat_ptr.rs @@ -8,8 +8,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -// ignore-pretty : (#23623) problems when ending with // comments - // check raw fat pointer ops in mir // FIXME: please improve this when we get monomorphization support diff --git a/src/test/run-pass/mod_dir_implicit.rs b/src/test/run-pass/mod_dir_implicit.rs index 1b89464c54..f8034f9e07 100644 --- a/src/test/run-pass/mod_dir_implicit.rs +++ b/src/test/run-pass/mod_dir_implicit.rs @@ -8,7 +8,7 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -// ignore-pretty +// ignore-pretty issue #37195 mod mod_dir_implicit_aux; diff --git a/src/test/run-pass/mod_dir_path.rs b/src/test/run-pass/mod_dir_path.rs index e0327a1dcd..e2f33963c4 100644 --- a/src/test/run-pass/mod_dir_path.rs +++ b/src/test/run-pass/mod_dir_path.rs @@ -8,7 +8,7 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -// ignore-pretty +// ignore-pretty issue #37195 mod mod_dir_simple { #[path = "test.rs"] @@ -17,4 +17,15 @@ mod mod_dir_simple { pub fn main() { assert_eq!(mod_dir_simple::syrup::foo(), 10); + + #[path = "auxiliary"] + mod foo { + mod two_macros; + } + + #[path = "auxiliary"] + mod bar { + macro_rules! m { () => { mod two_macros; } } + m!(); + } } diff --git a/src/test/run-pass/mod_dir_path2.rs b/src/test/run-pass/mod_dir_path2.rs index 2b5e67a6e8..b96c1ae072 100644 --- a/src/test/run-pass/mod_dir_path2.rs +++ b/src/test/run-pass/mod_dir_path2.rs @@ -8,7 +8,7 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -// ignore-pretty +// ignore-pretty issue #37195 #[path = "mod_dir_simple"] mod pancakes { diff --git a/src/test/run-pass/mod_dir_path3.rs b/src/test/run-pass/mod_dir_path3.rs index d6037bef6e..3160064d7c 100644 --- a/src/test/run-pass/mod_dir_path3.rs +++ b/src/test/run-pass/mod_dir_path3.rs @@ -8,7 +8,7 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -// ignore-pretty +// ignore-pretty issue #37195 #[path = "mod_dir_simple"] mod pancakes { diff --git a/src/test/run-pass/mod_dir_path_multi.rs b/src/test/run-pass/mod_dir_path_multi.rs index f1bf83ed76..12b28cf98a 100644 --- a/src/test/run-pass/mod_dir_path_multi.rs +++ b/src/test/run-pass/mod_dir_path_multi.rs @@ -8,7 +8,7 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -// ignore-pretty +// ignore-pretty issue #37195 #[path = "mod_dir_simple"] mod biscuits { diff --git a/src/test/run-pass/mod_dir_recursive.rs b/src/test/run-pass/mod_dir_recursive.rs index d7121ef769..8964d9ccd2 100644 --- a/src/test/run-pass/mod_dir_recursive.rs +++ b/src/test/run-pass/mod_dir_recursive.rs @@ -8,7 +8,7 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -// ignore-pretty +// ignore-pretty issue #37195 // Testing that the parser for each file tracks its modules // and paths independently. The load_another_mod module should diff --git a/src/test/run-pass/mod_dir_simple.rs b/src/test/run-pass/mod_dir_simple.rs index 41c810b6fd..429b4ebe63 100644 --- a/src/test/run-pass/mod_dir_simple.rs +++ b/src/test/run-pass/mod_dir_simple.rs @@ -8,7 +8,7 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -// ignore-pretty +// ignore-pretty issue #37195 mod mod_dir_simple { pub mod test; diff --git a/src/test/run-pass/mod_file.rs b/src/test/run-pass/mod_file.rs index ddda38bafd..c18fecd7c5 100644 --- a/src/test/run-pass/mod_file.rs +++ b/src/test/run-pass/mod_file.rs @@ -8,7 +8,7 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -// ignore-pretty +// ignore-pretty issue #37195 // Testing that a plain .rs file can load modules from other source files diff --git a/src/test/run-pass/mod_file_with_path_attr.rs b/src/test/run-pass/mod_file_with_path_attr.rs index c6e51daaaf..d9f28ceb0e 100644 --- a/src/test/run-pass/mod_file_with_path_attr.rs +++ b/src/test/run-pass/mod_file_with_path_attr.rs @@ -8,7 +8,7 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -// ignore-pretty +// ignore-pretty issue #37195 // Testing that a plain .rs file can load modules from other source files diff --git a/src/test/run-pass/monad.rs b/src/test/run-pass/monad.rs index b28e5ec64d..211827f922 100644 --- a/src/test/run-pass/monad.rs +++ b/src/test/run-pass/monad.rs @@ -45,9 +45,9 @@ fn transform(x: Option) -> Option { pub fn main() { assert_eq!(transform(Some(10)), Some("11".to_string())); assert_eq!(transform(None), None); - assert_eq!((vec!("hi".to_string())) - .bind(|x| vec!(x.clone(), format!("{}!", x)) ) - .bind(|x| vec!(x.clone(), format!("{}?", x)) ), + assert_eq!((vec!["hi".to_string()]) + .bind(|x| vec![x.clone(), format!("{}!", x)] ) + .bind(|x| vec![x.clone(), format!("{}?", x)] ), ["hi".to_string(), "hi?".to_string(), "hi!".to_string(), diff --git a/src/test/run-pass/move-arg-2-unique.rs b/src/test/run-pass/move-arg-2-unique.rs index bed339e158..0ff5a66adc 100644 --- a/src/test/run-pass/move-arg-2-unique.rs +++ b/src/test/run-pass/move-arg-2-unique.rs @@ -15,10 +15,10 @@ fn test(foo: Box> ) { assert_eq!((*foo)[0], 10); } pub fn main() { - let x = box vec!(10); + let x = box vec![10]; // Test forgetting a local by move-in test(x); // Test forgetting a temporary by move-in. - test(box vec!(10)); + test(box vec![10]); } diff --git a/src/test/run-pass/move-arg-2.rs b/src/test/run-pass/move-arg-2.rs index a6a26ab357..8de487bc36 100644 --- a/src/test/run-pass/move-arg-2.rs +++ b/src/test/run-pass/move-arg-2.rs @@ -15,10 +15,10 @@ fn test(foo: Box>) { assert_eq!((*foo)[0], 10); } pub fn main() { - let x = box vec!(10); + let x = box vec![10]; // Test forgetting a local by move-in test(x); // Test forgetting a temporary by move-in. - test(box vec!(10)); + test(box vec![10]); } diff --git a/src/test/run-pass/newtype-polymorphic.rs b/src/test/run-pass/newtype-polymorphic.rs index 91599608ce..e7da8d7bf9 100644 --- a/src/test/run-pass/newtype-polymorphic.rs +++ b/src/test/run-pass/newtype-polymorphic.rs @@ -24,7 +24,7 @@ fn myvec_elt(mv: myvec) -> X { } pub fn main() { - let mv = myvec(vec!(1, 2, 3)); + let mv = myvec(vec![1, 2, 3]); let mv_clone = mv.clone(); let mv_clone = myvec_deref(mv_clone); assert_eq!(mv_clone[1], 2); diff --git a/src/test/run-pass/nonzero-enum.rs b/src/test/run-pass/nonzero-enum.rs new file mode 100644 index 0000000000..266506e04b --- /dev/null +++ b/src/test/run-pass/nonzero-enum.rs @@ -0,0 +1,39 @@ +// Copyright 2016 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +use std::mem::size_of; + +enum E { + A = 1, + B = 2, + C = 3, +} + +struct S { + a: u16, + b: u8, + e: E, +} + +fn main() { + assert_eq!(size_of::(), 1); + assert_eq!(size_of::>(), 1); + assert_eq!(size_of::>(), 1); + assert_eq!(size_of::(), 4); + assert_eq!(size_of::>(), 4); + let enone = None::; + let esome = Some(E::A); + if let Some(..) = enone { + panic!(); + } + if let None = esome { + panic!(); + } +} diff --git a/src/test/run-pass/nullable-pointer-iotareduction.rs b/src/test/run-pass/nullable-pointer-iotareduction.rs index dffdcfe0af..7e8d082a28 100644 --- a/src/test/run-pass/nullable-pointer-iotareduction.rs +++ b/src/test/run-pass/nullable-pointer-iotareduction.rs @@ -76,7 +76,7 @@ pub fn main() { check_type!(&17, &isize); check_type!(box 18, Box); check_type!("foo".to_string(), String); - check_type!(vec!(20, 22), Vec); + check_type!(vec![20, 22], Vec); check_type!(main, fn(), |pthing| { assert_eq!(main as fn(), *pthing as fn()) }); diff --git a/src/test/run-pass/numeric-method-autoexport.rs b/src/test/run-pass/numeric-method-autoexport.rs index b1d71abc78..15ece09abd 100644 --- a/src/test/run-pass/numeric-method-autoexport.rs +++ b/src/test/run-pass/numeric-method-autoexport.rs @@ -8,8 +8,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -// no-pretty-expanded - // This file is intended to test only that methods are automatically // reachable for each numeric type, for each exported impl, with no imports // necessary. Testing the methods of the impls is done within the source 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 176f67fd3a..768f126e4e 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 @@ -32,11 +32,11 @@ impl FooTrait for BarStruct { } pub fn main() { - let foos: Vec> = vec!( + let foos: Vec> = vec![ box BarStruct{ x: 0 } as Box, box BarStruct{ x: 1 } as Box, box BarStruct{ x: 2 } as Box - ); + ]; for i in 0..foos.len() { assert_eq!(i, foos[i].foo()); diff --git a/src/test/run-pass/overloaded-deref.rs b/src/test/run-pass/overloaded-deref.rs index 8541c1c0a8..e2ca880719 100644 --- a/src/test/run-pass/overloaded-deref.rs +++ b/src/test/run-pass/overloaded-deref.rs @@ -45,7 +45,7 @@ pub fn main() { (*(*p).borrow_mut()).y += 3; assert_eq!(*(*p).borrow(), Point {x: 3, y: 5}); - let v = Rc::new(RefCell::new(vec!(1, 2, 3))); + let v = Rc::new(RefCell::new(vec![1, 2, 3])); (*(*v).borrow_mut())[0] = 3; (*(*v).borrow_mut())[1] += 3; assert_eq!(((*(*v).borrow())[0], diff --git a/src/test/run-pass/packed-struct-layout.rs b/src/test/run-pass/packed-struct-layout.rs index 92308c9fc3..d1e05e5a01 100644 --- a/src/test/run-pass/packed-struct-layout.rs +++ b/src/test/run-pass/packed-struct-layout.rs @@ -7,6 +7,7 @@ // , at your // option. This file may not be copied, modified, or distributed // except according to those terms. +// ignore-emscripten Not sure what's happening here. 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 411c1807a1..ee4eb86ed0 100644 --- a/src/test/run-pass/packed-tuple-struct-layout.rs +++ b/src/test/run-pass/packed-tuple-struct-layout.rs @@ -7,6 +7,7 @@ // , at your // option. This file may not be copied, modified, or distributed // except according to those terms. +// ignore-emscripten use std::mem; diff --git a/src/test/run-pass/panic-runtime/abort-link-to-unwinding-crates.rs b/src/test/run-pass/panic-runtime/abort-link-to-unwinding-crates.rs index 71c1a61062..1c273fcba0 100644 --- a/src/test/run-pass/panic-runtime/abort-link-to-unwinding-crates.rs +++ b/src/test/run-pass/panic-runtime/abort-link-to-unwinding-crates.rs @@ -11,6 +11,7 @@ // compile-flags:-C panic=abort // aux-build:exit-success-if-unwind.rs // no-prefer-dynamic +// ignore-emscripten Function not implemented extern crate exit_success_if_unwind; diff --git a/src/test/run-pass/panic-runtime/abort.rs b/src/test/run-pass/panic-runtime/abort.rs index 2fc9d6cfd0..be38f6ea36 100644 --- a/src/test/run-pass/panic-runtime/abort.rs +++ b/src/test/run-pass/panic-runtime/abort.rs @@ -10,6 +10,7 @@ // compile-flags:-C panic=abort // no-prefer-dynamic +// ignore-emscripten Function not implemented. use std::process::Command; use std::env; diff --git a/src/test/run-pass/panic-runtime/lto-abort.rs b/src/test/run-pass/panic-runtime/lto-abort.rs index 09e33b8818..e4cd4e809a 100644 --- a/src/test/run-pass/panic-runtime/lto-abort.rs +++ b/src/test/run-pass/panic-runtime/lto-abort.rs @@ -10,6 +10,7 @@ // compile-flags:-C lto -C panic=abort // no-prefer-dynamic +// ignore-emscripten Function not implemented. use std::process::Command; use std::env; diff --git a/src/test/run-pass/panic-runtime/lto-unwind.rs b/src/test/run-pass/panic-runtime/lto-unwind.rs index 10e633b377..768b88fd09 100644 --- a/src/test/run-pass/panic-runtime/lto-unwind.rs +++ b/src/test/run-pass/panic-runtime/lto-unwind.rs @@ -10,6 +10,7 @@ // compile-flags:-C lto -C panic=unwind // no-prefer-dynamic +// ignore-emscripten Function not implemented. use std::process::Command; use std::env; diff --git a/src/test/run-pass/pat-tuple-1.rs b/src/test/run-pass/pat-tuple-1.rs index c3796210a8..45a9a2b303 100644 --- a/src/test/run-pass/pat-tuple-1.rs +++ b/src/test/run-pass/pat-tuple-1.rs @@ -8,8 +8,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -#![feature(dotdot_in_tuple_patterns)] - fn tuple() { let x = (1, 2, 3); match x { diff --git a/src/test/run-pass/pat-tuple-2.rs b/src/test/run-pass/pat-tuple-2.rs index 881e96a9d7..ee60d1c01c 100644 --- a/src/test/run-pass/pat-tuple-2.rs +++ b/src/test/run-pass/pat-tuple-2.rs @@ -8,8 +8,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -#![feature(dotdot_in_tuple_patterns)] - fn tuple() { let x = (1,); match x { diff --git a/src/test/run-pass/pat-tuple-3.rs b/src/test/run-pass/pat-tuple-3.rs index 94d33d4189..7a46c1deb5 100644 --- a/src/test/run-pass/pat-tuple-3.rs +++ b/src/test/run-pass/pat-tuple-3.rs @@ -8,8 +8,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -#![feature(dotdot_in_tuple_patterns)] - fn tuple() { let x = (1, 2, 3); let branch = match x { diff --git a/src/test/run-pass/pat-tuple-4.rs b/src/test/run-pass/pat-tuple-4.rs index ffd82fea99..1d75e1e9d1 100644 --- a/src/test/run-pass/pat-tuple-4.rs +++ b/src/test/run-pass/pat-tuple-4.rs @@ -8,8 +8,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -#![feature(dotdot_in_tuple_patterns)] - fn tuple() { let x = (1, 2, 3); match x { diff --git a/src/test/run-pass/pat-tuple-5.rs b/src/test/run-pass/pat-tuple-5.rs index 41c4d02abc..1192932f13 100644 --- a/src/test/run-pass/pat-tuple-5.rs +++ b/src/test/run-pass/pat-tuple-5.rs @@ -8,8 +8,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -#![feature(dotdot_in_tuple_patterns)] - fn tuple() { struct S; struct Z; diff --git a/src/test/run-pass/pat-tuple-6.rs b/src/test/run-pass/pat-tuple-6.rs index 6f3f2b3aed..9d3cd65b45 100644 --- a/src/test/run-pass/pat-tuple-6.rs +++ b/src/test/run-pass/pat-tuple-6.rs @@ -8,8 +8,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -#![feature(dotdot_in_tuple_patterns)] - fn tuple() { let x = (1, 2, 3, 4, 5); match x { diff --git a/src/test/run-pass/process-status-inherits-stdin.rs b/src/test/run-pass/process-status-inherits-stdin.rs index 2ad47c4f11..ff389bec89 100644 --- a/src/test/run-pass/process-status-inherits-stdin.rs +++ b/src/test/run-pass/process-status-inherits-stdin.rs @@ -7,6 +7,7 @@ // , at your // option. This file may not be copied, modified, or distributed // except according to those terms. +// ignore-emscripten Function not implemented. use std::env; use std::io; diff --git a/src/test/run-pass/project-cache-issue-37154.rs b/src/test/run-pass/project-cache-issue-37154.rs new file mode 100644 index 0000000000..29dc6984e2 --- /dev/null +++ b/src/test/run-pass/project-cache-issue-37154.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. + +// Regression test for #37154: the problem here was that the cache +// results in a false error because it was caching skolemized results +// even after those skolemized regions had been popped. + +trait Foo { + fn method(&self) {} +} + +struct Wrapper(T); + +impl Foo for Wrapper where for<'a> &'a T: IntoIterator {} + +fn f(x: Wrapper>) { + x.method(); // This works. + x.method(); // error: no method named `method` +} + +fn main() { } diff --git a/src/test/run-pass/range_inclusive.rs b/src/test/run-pass/range_inclusive.rs index aaf129e7b8..cfa9f6e36e 100644 --- a/src/test/run-pass/range_inclusive.rs +++ b/src/test/run-pass/range_inclusive.rs @@ -75,7 +75,7 @@ pub fn main() { // test the size hints and emptying let mut long = 0...255u8; - let mut short = 42...42; + let mut short = 42...42u8; assert_eq!(long.size_hint(), (256, Some(256))); assert_eq!(short.size_hint(), (1, Some(1))); long.next(); diff --git a/src/test/run-pass/rcvr-borrowed-to-slice.rs b/src/test/run-pass/rcvr-borrowed-to-slice.rs index 1ec1674718..efa73ad92c 100644 --- a/src/test/run-pass/rcvr-borrowed-to-slice.rs +++ b/src/test/run-pass/rcvr-borrowed-to-slice.rs @@ -23,17 +23,17 @@ impl<'a> sum for &'a [isize] { fn call_sum(x: &[isize]) -> isize { x.sum_() } pub fn main() { - let x = vec!(1, 2, 3); + let x = vec![1, 2, 3]; let y = call_sum(&x); println!("y=={}", y); assert_eq!(y, 6); - let x = vec!(1, 2, 3); + let x = vec![1, 2, 3]; let y = x.sum_(); println!("y=={}", y); assert_eq!(y, 6); - let x = vec!(1, 2, 3); + let x = vec![1, 2, 3]; let y = x.sum_(); println!("y=={}", y); assert_eq!(y, 6); diff --git a/src/test/run-pass/reexport-test-harness-main.rs b/src/test/run-pass/reexport-test-harness-main.rs index 309ae1bcc5..88e3e6ba4a 100644 --- a/src/test/run-pass/reexport-test-harness-main.rs +++ b/src/test/run-pass/reexport-test-harness-main.rs @@ -8,7 +8,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -// ignore-pretty // compile-flags:--test #![reexport_test_harness_main = "test_main"] diff --git a/src/test/run-pass/regions-borrow-evec-uniq.rs b/src/test/run-pass/regions-borrow-evec-uniq.rs index ec1f4eda28..e61a8d1477 100644 --- a/src/test/run-pass/regions-borrow-evec-uniq.rs +++ b/src/test/run-pass/regions-borrow-evec-uniq.rs @@ -15,11 +15,11 @@ fn foo(x: &[isize]) -> isize { } pub fn main() { - let p = vec!(1,2,3,4,5); + let p = vec![1,2,3,4,5]; let r = foo(&p); assert_eq!(r, 1); - let p = vec!(5,4,3,2,1); + let p = vec![5,4,3,2,1]; let r = foo(&p); assert_eq!(r, 5); } diff --git a/src/test/run-pass/regions-bound-lists-feature-gate-2.rs b/src/test/run-pass/regions-bound-lists-feature-gate-2.rs index a06e0f6da7..47d2fe363d 100644 --- a/src/test/run-pass/regions-bound-lists-feature-gate-2.rs +++ b/src/test/run-pass/regions-bound-lists-feature-gate-2.rs @@ -8,8 +8,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -// ignore-pretty - #![feature(issue_5723_bootstrap)] trait Foo { diff --git a/src/test/run-pass/regions-bound-lists-feature-gate.rs b/src/test/run-pass/regions-bound-lists-feature-gate.rs index 996583dc6d..72db92aa93 100644 --- a/src/test/run-pass/regions-bound-lists-feature-gate.rs +++ b/src/test/run-pass/regions-bound-lists-feature-gate.rs @@ -8,8 +8,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -// ignore-pretty - #![feature(issue_5723_bootstrap)] trait Foo { diff --git a/src/test/run-pass/regions-dependent-addr-of.rs b/src/test/run-pass/regions-dependent-addr-of.rs index a6a179c432..e9a3e16438 100644 --- a/src/test/run-pass/regions-dependent-addr-of.rs +++ b/src/test/run-pass/regions-dependent-addr-of.rs @@ -90,7 +90,7 @@ fn get_v5_ref(a: &A, _i: usize) -> &isize { pub fn main() { let a = A {value: B {v1: 22, v2: [23, 24, 25], - v3: vec!(26, 27, 28), + v3: vec![26, 27, 28], v4: C { f: 29 }, v5: box C { f: 30 }, v6: Some(C { f: 31 })}}; diff --git a/src/test/run-pass/regions-dependent-autoslice.rs b/src/test/run-pass/regions-dependent-autoslice.rs index 7183937fe8..cd140f7aa5 100644 --- a/src/test/run-pass/regions-dependent-autoslice.rs +++ b/src/test/run-pass/regions-dependent-autoslice.rs @@ -18,6 +18,6 @@ fn both<'r>(v: &'r [usize]) -> &'r [usize] { } pub fn main() { - let v = vec!(1,2,3); + let v = vec![1,2,3]; both(&v); } 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 f9ba8e82ef..262e936826 100644 --- a/src/test/run-pass/regions-infer-borrow-scope-view.rs +++ b/src/test/run-pass/regions-infer-borrow-scope-view.rs @@ -13,7 +13,7 @@ fn view(x: &[T]) -> &[T] {x} pub fn main() { - let v = vec!(1, 2, 3); + let v = vec![1, 2, 3]; let x = view(&v); let y = view(x); assert!((v[0] == x[0]) && (v[0] == y[0])); 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 465f43e36b..8eee54b3fe 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 @@ -63,7 +63,7 @@ impl<'a,'tcx> Foo<'a,'tcx> { } fn main() { - let v = vec!(); + let v = vec![]; let cx = Ctxt { x: &v }; let mut foo = Foo { cx: &cx }; assert_eq!(foo.bother(), 22); // just so the code is not dead, basically diff --git a/src/test/run-pass/seq-compare.rs b/src/test/run-pass/seq-compare.rs index f1a21d90ab..43612f5297 100644 --- a/src/test/run-pass/seq-compare.rs +++ b/src/test/run-pass/seq-compare.rs @@ -14,13 +14,13 @@ pub fn main() { assert!(("hello".to_string() < "hellr".to_string())); assert!(("hello ".to_string() > "hello".to_string())); assert!(("hello".to_string() != "there".to_string())); - assert!((vec!(1, 2, 3, 4) > vec!(1, 2, 3))); - assert!((vec!(1, 2, 3) < vec!(1, 2, 3, 4))); - assert!((vec!(1, 2, 4, 4) > vec!(1, 2, 3, 4))); - assert!((vec!(1, 2, 3, 4) < vec!(1, 2, 4, 4))); - assert!((vec!(1, 2, 3) <= vec!(1, 2, 3))); - assert!((vec!(1, 2, 3) <= vec!(1, 2, 3, 3))); - assert!((vec!(1, 2, 3, 4) > vec!(1, 2, 3))); - assert_eq!(vec!(1, 2, 3), vec!(1, 2, 3)); - assert!((vec!(1, 2, 3) != vec!(1, 1, 3))); + assert!((vec![1, 2, 3, 4] > vec![1, 2, 3])); + assert!((vec![1, 2, 3] < vec![1, 2, 3, 4])); + assert!((vec![1, 2, 4, 4] > vec![1, 2, 3, 4])); + assert!((vec![1, 2, 3, 4] < vec![1, 2, 4, 4])); + assert!((vec![1, 2, 3] <= vec![1, 2, 3])); + assert!((vec![1, 2, 3] <= vec![1, 2, 3, 3])); + assert!((vec![1, 2, 3, 4] > vec![1, 2, 3])); + assert_eq!(vec![1, 2, 3], vec![1, 2, 3]); + assert!((vec![1, 2, 3] != vec![1, 1, 3])); } diff --git a/src/test/run-pass/shebang.rs b/src/test/run-pass/shebang.rs index 15ab21bbc8..a0947cd49a 100644 --- a/src/test/run-pass/shebang.rs +++ b/src/test/run-pass/shebang.rs @@ -9,7 +9,4 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -// ignore-pretty: `expand` adds some preludes before shebang -// - pub fn main() { println!("Hello World"); } diff --git a/src/test/run-pass/simd-intrinsic-generic-cast.rs b/src/test/run-pass/simd-intrinsic-generic-cast.rs index 2efd933399..d32fa01c7b 100644 --- a/src/test/run-pass/simd-intrinsic-generic-cast.rs +++ b/src/test/run-pass/simd-intrinsic-generic-cast.rs @@ -7,6 +7,7 @@ // , at your // option. This file may not be copied, modified, or distributed // except according to those terms. +// ignore-emscripten linking with emcc failed #![feature(repr_simd, platform_intrinsics, concat_idents, test)] #![allow(non_camel_case_types)] diff --git a/src/test/run-pass/simd-intrinsic-generic-elements.rs b/src/test/run-pass/simd-intrinsic-generic-elements.rs index 5cb57b63ad..f0444c2717 100644 --- a/src/test/run-pass/simd-intrinsic-generic-elements.rs +++ b/src/test/run-pass/simd-intrinsic-generic-elements.rs @@ -10,8 +10,6 @@ #![feature(repr_simd, platform_intrinsics)] -// ignore-pretty : (#23623) problems when ending with // comments - #[repr(simd)] #[derive(Copy, Clone, Debug, PartialEq)] #[allow(non_camel_case_types)] diff --git a/src/test/run-pass/size-and-align.rs b/src/test/run-pass/size-and-align.rs index 007ce52d7c..13d55e0172 100644 --- a/src/test/run-pass/size-and-align.rs +++ b/src/test/run-pass/size-and-align.rs @@ -22,6 +22,6 @@ fn uhoh(v: Vec> ) { } pub fn main() { - let v: Vec> = vec!(clam::b::, clam::b::, clam::a::(42, 17)); + let v: Vec> = vec![clam::b::, clam::b::, clam::a::(42, 17)]; uhoh::(v); } diff --git a/src/test/run-pass/static-impl.rs b/src/test/run-pass/static-impl.rs index 84bb1b871b..89fd83ced4 100644 --- a/src/test/run-pass/static-impl.rs +++ b/src/test/run-pass/static-impl.rs @@ -62,10 +62,10 @@ pub fn main() { assert_eq!(10_usize.plus(), 30); assert_eq!(("hi".to_string()).plus(), 200); - assert_eq!((vec!(1)).length_().str(), "1".to_string()); - let vect = vec!(3, 4).map_(|a| *a + 4); + assert_eq!((vec![1]).length_().str(), "1".to_string()); + let vect = vec![3, 4].map_(|a| *a + 4); assert_eq!(vect[0], 7); - let vect = (vec!(3, 4)).map_::(|a| *a as usize + 4_usize); + let vect = (vec![3, 4]).map_::(|a| *a as usize + 4_usize); assert_eq!(vect[0], 7_usize); let mut x = 0_usize; 10_usize.multi(|_n| x += 2_usize ); diff --git a/src/test/run-pass/struct-field-shorthand.rs b/src/test/run-pass/struct-field-shorthand.rs new file mode 100644 index 0000000000..fe91db572d --- /dev/null +++ b/src/test/run-pass/struct-field-shorthand.rs @@ -0,0 +1,37 @@ +// 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(field_init_shorthand)] + +struct Foo { + x: i32, + y: bool, + z: i32 +} + +struct Bar { + x: i32 +} + +pub fn main() { + let (x, y, z) = (1, true, 2); + let a = Foo { x, y: y, z }; + assert_eq!(a.x, x); + assert_eq!(a.y, y); + assert_eq!(a.z, z); + + let b = Bar { x, }; + assert_eq!(b.x, x); + + let c = Foo { z, y, x }; + assert_eq!(c.x, x); + assert_eq!(c.y, y); + assert_eq!(c.z, z); +} diff --git a/src/test/compile-fail/struct-pat-associated-path.rs b/src/test/run-pass/struct-path-associated-type.rs similarity index 59% rename from src/test/compile-fail/struct-pat-associated-path.rs rename to src/test/run-pass/struct-path-associated-type.rs index d3f840f4fe..292761dfd0 100644 --- a/src/test/compile-fail/struct-pat-associated-path.rs +++ b/src/test/run-pass/struct-path-associated-type.rs @@ -8,30 +8,30 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -struct S; +#![feature(more_struct_aliases)] + +struct S { + a: T, + b: U, +} trait Tr { type A; } - -impl Tr for S { - type A = S; +impl Tr for u8 { + type A = S; } -fn f() { - match S { - T::A {} => {} //~ ERROR `T::A` does not name a struct or a struct variant - } -} - -fn g>() { - match S { - T::A {} => {} //~ ERROR `T::A` does not name a struct or a struct variant +fn f>>() { + let s = T::A { a: 0, b: 1 }; + match s { + T::A { a, b } => { + assert_eq!(a, 0); + assert_eq!(b, 1); + } } } fn main() { - match S { - S::A {} => {} //~ ERROR ambiguous associated type - } + f::(); } diff --git a/src/test/run-pass/struct-path-self.rs b/src/test/run-pass/struct-path-self.rs new file mode 100644 index 0000000000..b569ab62c1 --- /dev/null +++ b/src/test/run-pass/struct-path-self.rs @@ -0,0 +1,56 @@ +// Copyright 2016 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +#![feature(more_struct_aliases)] + +use std::ops::Add; + +struct S { + a: T, + b: U, +} + +trait Tr { + fn f(&self) -> Self; +} + +impl, U: Default> Tr for S { + fn f(&self) -> Self { + let s = Self { a: Default::default(), b: Default::default() }; + match s { + Self { a, b } => Self { a: a + 1, b: b } + } + } +} + +impl> S { + fn g(&self) -> Self { + let s = Self { a: Default::default(), b: Default::default() }; + match s { + Self { a, b } => Self { a: a, b: b + 1 } + } + } +} + +impl S { + fn new() -> Self { + Self { a: 0, b: 1 } + } +} + +fn main() { + let s0 = S::new(); + let s1 = s0.f(); + assert_eq!(s1.a, 1); + assert_eq!(s1.b, 0); + let s2 = s0.g(); + assert_eq!(s2.a, 0); + assert_eq!(s2.b, 1); +} diff --git a/src/test/run-pass/super-fast-paren-parsing.rs b/src/test/run-pass/super-fast-paren-parsing.rs index b764a983a0..a1bbd19021 100644 --- a/src/test/run-pass/super-fast-paren-parsing.rs +++ b/src/test/run-pass/super-fast-paren-parsing.rs @@ -8,8 +8,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -// ignore-pretty -// // exec-env:RUST_MIN_STACK=16000000 // rustc-env:RUST_MIN_STACK=16000000 // diff --git a/src/test/run-pass/swap-2.rs b/src/test/run-pass/swap-2.rs index 3dbd7f1a60..4601b7d7cf 100644 --- a/src/test/run-pass/swap-2.rs +++ b/src/test/run-pass/swap-2.rs @@ -12,7 +12,7 @@ use std::mem::swap; pub fn main() { - let mut a: Vec = vec!(0, 1, 2, 3, 4, 5, 6); + let mut a: Vec = vec![0, 1, 2, 3, 4, 5, 6]; a.swap(2, 4); assert_eq!(a[2], 4); assert_eq!(a[4], 2); diff --git a/src/test/run-pass/syntax-extension-source-utils.rs b/src/test/run-pass/syntax-extension-source-utils.rs index 2f52e42493..3b5f033d07 100644 --- a/src/test/run-pass/syntax-extension-source-utils.rs +++ b/src/test/run-pass/syntax-extension-source-utils.rs @@ -8,10 +8,7 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -#![feature(core)] - -// This test is brittle! -// ignore-pretty - the pretty tests lose path information, breaking include! +// ignore-pretty issue #37195 pub mod m1 { pub mod m2 { @@ -24,9 +21,9 @@ pub mod m1 { macro_rules! indirect_line { () => ( line!() ) } pub fn main() { - assert_eq!(line!(), 27); + assert_eq!(line!(), 24); assert_eq!(column!(), 4); - assert_eq!(indirect_line!(), 29); + assert_eq!(indirect_line!(), 26); assert!((file!().ends_with("syntax-extension-source-utils.rs"))); assert_eq!(stringify!((2*3) + 5).to_string(), "( 2 * 3 ) + 5".to_string()); assert!(include!("syntax-extension-source-utils-files/includeme.\ @@ -43,5 +40,5 @@ pub fn main() { // The Windows tests are wrapped in an extra module for some reason assert!((m1::m2::where_am_i().ends_with("m1::m2"))); - assert_eq!((46, "( 2 * 3 ) + 5"), (line!(), stringify!((2*3) + 5))); + assert_eq!((43, "( 2 * 3 ) + 5"), (line!(), stringify!((2*3) + 5))); } diff --git a/src/test/run-pass/task-comm-16.rs b/src/test/run-pass/task-comm-16.rs index c6d8f3c0d9..0caf21ead3 100644 --- a/src/test/run-pass/task-comm-16.rs +++ b/src/test/run-pass/task-comm-16.rs @@ -27,7 +27,7 @@ fn test_rec() { fn test_vec() { let (tx, rx) = channel(); - let v0: Vec = vec!(0, 1, 2); + let v0: Vec = vec![0, 1, 2]; tx.send(v0).unwrap(); let v1 = rx.recv().unwrap(); assert_eq!(v1[0], 0); diff --git a/src/test/run-pass/task-comm-3.rs b/src/test/run-pass/task-comm-3.rs index 0e8542baba..78f29f46ed 100644 --- a/src/test/run-pass/task-comm-3.rs +++ b/src/test/run-pass/task-comm-3.rs @@ -11,7 +11,6 @@ #![feature(std_misc)] // ignore-emscripten no threads support -// no-pretty-expanded FIXME #15189 use std::thread; use std::sync::mpsc::{channel, Sender}; diff --git a/src/test/run-pass/task-stderr.rs b/src/test/run-pass/task-stderr.rs index 1f64f40c52..13d5cc989e 100644 --- a/src/test/run-pass/task-stderr.rs +++ b/src/test/run-pass/task-stderr.rs @@ -30,7 +30,7 @@ fn main() { let data = Arc::new(Mutex::new(Vec::new())); let sink = Sink(data.clone()); let res = thread::Builder::new().spawn(move|| -> () { - io::set_panic(Box::new(sink)); + io::set_panic(Some(Box::new(sink))); panic!("Hello, world!") }).unwrap().join(); assert!(res.is_err()); diff --git a/src/test/run-pass/test-fn-signature-verification-for-explicit-return-type.rs b/src/test/run-pass/test-fn-signature-verification-for-explicit-return-type.rs index d58b5d3a00..10ad838d3c 100644 --- a/src/test/run-pass/test-fn-signature-verification-for-explicit-return-type.rs +++ b/src/test/run-pass/test-fn-signature-verification-for-explicit-return-type.rs @@ -11,7 +11,6 @@ #![feature(test)] // compile-flags: --test -// no-pretty-expanded extern crate test; #[bench] diff --git a/src/test/run-pass/test-runner-hides-main.rs b/src/test/run-pass/test-runner-hides-main.rs index 839e91f379..7b696c1f8d 100644 --- a/src/test/run-pass/test-runner-hides-main.rs +++ b/src/test/run-pass/test-runner-hides-main.rs @@ -9,8 +9,6 @@ // except according to those terms. // compile-flags:--test -// ignore-pretty: does not work well with `--test` - // Building as a test runner means that a synthetic main will be run, // not ours pub fn main() { panic!(); } diff --git a/src/test/run-pass/test-should-fail-good-message.rs b/src/test/run-pass/test-should-fail-good-message.rs index 2869849930..e665fa4fc7 100644 --- a/src/test/run-pass/test-should-fail-good-message.rs +++ b/src/test/run-pass/test-should-fail-good-message.rs @@ -9,8 +9,6 @@ // except according to those terms. // compile-flags: --test -// ignore-pretty: does not work well with `--test` - #[test] #[should_panic(expected = "foo")] pub fn test_foo() { diff --git a/src/test/run-pass/trait-bounds-in-arc.rs b/src/test/run-pass/trait-bounds-in-arc.rs index 0de6fbc91c..9877dffe9d 100644 --- a/src/test/run-pass/trait-bounds-in-arc.rs +++ b/src/test/run-pass/trait-bounds-in-arc.rs @@ -12,8 +12,6 @@ // and shared between threads as long as all types fulfill Send. // ignore-emscripten no threads support -// ignore-pretty - #![allow(unknown_features)] #![feature(box_syntax, std_misc)] @@ -77,10 +75,10 @@ pub fn main() { swim_speed: 998, name: "alec_guinness".to_string(), }; - let arc = Arc::new(vec!(box catte as Box, + let arc = Arc::new(vec![box catte as Box, box dogge1 as Box, box fishe as Box, - box dogge2 as Box)); + box dogge2 as Box]); let (tx1, rx1) = channel(); let arc1 = arc.clone(); let t1 = thread::spawn(move|| { check_legs(arc1); tx1.send(()); }); diff --git a/src/test/run-pass/trait-generic.rs b/src/test/run-pass/trait-generic.rs index 4998236629..eadda5dfe2 100644 --- a/src/test/run-pass/trait-generic.rs +++ b/src/test/run-pass/trait-generic.rs @@ -45,9 +45,9 @@ fn bar>(x: T) -> Vec { } pub fn main() { - assert_eq!(foo(vec!(1)), ["hi".to_string()]); - assert_eq!(bar:: >(vec!(4, 5)), ["4".to_string(), "5".to_string()]); - assert_eq!(bar:: >(vec!("x".to_string(), "y".to_string())), + assert_eq!(foo(vec![1]), ["hi".to_string()]); + assert_eq!(bar:: >(vec![4, 5]), ["4".to_string(), "5".to_string()]); + assert_eq!(bar:: >(vec!["x".to_string(), "y".to_string()]), ["x".to_string(), "y".to_string()]); - assert_eq!(bar::<(), Vec<()>>(vec!(())), ["()".to_string()]); + assert_eq!(bar::<(), Vec<()>>(vec![()]), ["()".to_string()]); } diff --git a/src/test/run-pass/trait-to-str.rs b/src/test/run-pass/trait-to-str.rs index f5af05d872..9671e31d7e 100644 --- a/src/test/run-pass/trait-to-str.rs +++ b/src/test/run-pass/trait-to-str.rs @@ -30,15 +30,15 @@ impl to_str for Vec { pub fn main() { assert_eq!(1.to_string_(), "1".to_string()); - assert_eq!((vec!(2, 3, 4)).to_string_(), "[2, 3, 4]".to_string()); + assert_eq!((vec![2, 3, 4]).to_string_(), "[2, 3, 4]".to_string()); fn indirect(x: T) -> String { format!("{}!", x.to_string_()) } - assert_eq!(indirect(vec!(10, 20)), "[10, 20]!".to_string()); + assert_eq!(indirect(vec![10, 20]), "[10, 20]!".to_string()); fn indirect2(x: T) -> String { indirect(x) } - assert_eq!(indirect2(vec!(1)), "[1]!".to_string()); + assert_eq!(indirect2(vec![1]), "[1]!".to_string()); } diff --git a/src/test/run-pass/traits-elaborate-type-region.rs b/src/test/run-pass/traits-elaborate-type-region.rs new file mode 100644 index 0000000000..4621c2ca4b --- /dev/null +++ b/src/test/run-pass/traits-elaborate-type-region.rs @@ -0,0 +1,58 @@ +// Copyright 2016 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +#![allow(dead_code)] + +// Test that we elaborate `Type: 'region` constraints and infer various important things. + +trait Master<'a, T: ?Sized> { + fn foo() where T: 'a; +} + +// [U]: 'a => U: 'a +impl<'a, U> Master<'a, [U]> for () { + fn foo() where U: 'a { } +} + +// &'b U: 'a => 'b: 'a, U: 'a +impl<'a, 'b, U> Master<'a, &'b U> for () { + fn foo() where 'b: 'a, U: 'a { } +} + +// &'b [U]: 'a => 'b: 'a, U: 'a +impl<'a, 'b, U> Master<'a, &'b [U]> for () { + fn foo() where 'b: 'a, U: 'a { } +} + +// Foo<'b>: 'a => 'b: 'a +struct Foo<'a> { x: &'a () } +impl<'a, 'b> Master<'a, Foo<'b>> for () { + fn foo() where 'b: 'a { } +} + +// Bar<'b, T>: 'a => 'b: 'a, T: 'a +struct Bar<'a, T: 'a> { x: &'a T } +impl<'a, 'b, T> Master<'a, Bar<'b, T>> for () { + fn foo() where 'b: 'a, T: 'a { } +} + +// fn(T): 'a => T: 'a +impl<'a, T> Master<'a, fn(T)> for () { + fn foo() where T: 'a { } +} + +// fn() -> T: 'a => T: 'a +impl<'a, T> Master<'a, fn() -> T> for () { + fn foo() where T: 'a { } +} + +fn main() { + println!("Hello, world!"); +} diff --git a/src/test/run-pass/type-macros-simple.rs b/src/test/run-pass/type-macros-simple.rs index 6b0deff3ba..c61133f795 100644 --- a/src/test/run-pass/type-macros-simple.rs +++ b/src/test/run-pass/type-macros-simple.rs @@ -23,7 +23,7 @@ fn issue_36540() { let x: m!() = m!(); std::cell::Cell::::new(m!()); - impl std::ops::Index for Trait<(m!(), T)> + impl std::ops::Index for Trait<(m!(), T)> where T: Trait { type Output = m!(); diff --git a/src/test/run-pass/typeck-fn-to-unsafe-fn-ptr.rs b/src/test/run-pass/typeck-fn-to-unsafe-fn-ptr.rs new file mode 100644 index 0000000000..323705f3f9 --- /dev/null +++ b/src/test/run-pass/typeck-fn-to-unsafe-fn-ptr.rs @@ -0,0 +1,21 @@ +// 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. + +// This tests reification from safe function to `unsafe fn` pointer + +fn do_nothing() -> () {} + +unsafe fn call_unsafe(func: unsafe fn() -> ()) -> () { + func() +} + +pub fn main() { + unsafe { call_unsafe(do_nothing); } +} 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 0b85916d22..300a0ee63f 100644 --- a/src/test/run-pass/unboxed-closures-counter-not-moved.rs +++ b/src/test/run-pass/unboxed-closures-counter-not-moved.rs @@ -15,7 +15,7 @@ fn call(f: F) where F : FnOnce() { } fn main() { - let y = vec!(format!("Hello"), format!("World")); + let y = vec![format!("Hello"), format!("World")]; let mut counter = 22_u32; call(|| { 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 9966364625..b9a16535c4 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 @@ -16,8 +16,8 @@ fn call(f: F) where F : FnOnce() { } fn main() { - let mut x = vec!(format!("Hello")); - let y = vec!(format!("World")); + let mut x = vec![format!("Hello")]; + let y = vec![format!("World")]; call(|| { // Here: `x` must be captured with a mutable reference in // order for us to append on it, and `y` must be captured by diff --git a/src/test/run-pass/union/union-backcomp.rs b/src/test/run-pass/union/union-backcomp.rs index 9394b618dd..0f8c996beb 100644 --- a/src/test/run-pass/union/union-backcomp.rs +++ b/src/test/run-pass/union/union-backcomp.rs @@ -10,6 +10,12 @@ #![feature(untagged_unions)] +macro_rules! union { + () => (struct S;) +} + +union!(); + fn union() {} fn main() { diff --git a/src/test/run-pass/union/union-with-drop-fields-lint.rs b/src/test/run-pass/union/union-with-drop-fields-lint.rs index 5a1424830d..6cb7e82d6b 100644 --- a/src/test/run-pass/union/union-with-drop-fields-lint.rs +++ b/src/test/run-pass/union/union-with-drop-fields-lint.rs @@ -8,8 +8,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -// ignore-pretty - #![feature(untagged_unions)] #![allow(dead_code)] #![allow(unions_with_drop_fields)] 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 baca157a48..7910380abe 100644 --- a/src/test/run-pass/uniq-self-in-mut-slot.rs +++ b/src/test/run-pass/uniq-self-in-mut-slot.rs @@ -17,7 +17,7 @@ struct X { } trait Changer { - fn change(mut self: Box) -> Box; + fn change(self: Box) -> Box; } impl Changer for X { diff --git a/src/test/run-pass/unique-autoderef-index.rs b/src/test/run-pass/unique-autoderef-index.rs index c68ff1f061..1ef61008b3 100644 --- a/src/test/run-pass/unique-autoderef-index.rs +++ b/src/test/run-pass/unique-autoderef-index.rs @@ -13,6 +13,6 @@ #![feature(box_syntax)] pub fn main() { - let i: Box<_> = box vec!(100); + let i: Box<_> = box vec![100]; assert_eq!((*i)[0], 100); } diff --git a/src/test/run-pass/unique-create.rs b/src/test/run-pass/unique-create.rs index 8469ae7020..6d638bbf56 100644 --- a/src/test/run-pass/unique-create.rs +++ b/src/test/run-pass/unique-create.rs @@ -18,5 +18,5 @@ pub fn main() { } fn vec() { - vec!(0); + vec![0]; } diff --git a/src/test/run-pass/unique-drop-complex.rs b/src/test/run-pass/unique-drop-complex.rs index 056acd1620..1910d51bd0 100644 --- a/src/test/run-pass/unique-drop-complex.rs +++ b/src/test/run-pass/unique-drop-complex.rs @@ -14,5 +14,5 @@ #![feature(box_syntax)] pub fn main() { - let _x: Box<_> = box vec!(0,0,0,0,0); + let _x: Box<_> = box vec![0,0,0,0,0]; } diff --git a/src/test/run-pass/unique-in-vec-copy.rs b/src/test/run-pass/unique-in-vec-copy.rs index ab0e3ee809..ece206caa0 100644 --- a/src/test/run-pass/unique-in-vec-copy.rs +++ b/src/test/run-pass/unique-in-vec-copy.rs @@ -13,7 +13,7 @@ #![feature(box_syntax)] pub fn main() { - let mut a: Vec> = vec!(box 10); + let mut a: Vec> = vec![box 10]; let b = a.clone(); assert_eq!(*a[0], 10); diff --git a/src/test/run-pass/unique-in-vec.rs b/src/test/run-pass/unique-in-vec.rs index 026bc0435d..bd965d41ee 100644 --- a/src/test/run-pass/unique-in-vec.rs +++ b/src/test/run-pass/unique-in-vec.rs @@ -13,6 +13,6 @@ #![feature(box_syntax)] pub fn main() { - let vect : Vec> = vec!(box 100); + let vect : Vec> = vec![box 100]; assert_eq!(vect[0], box 100); } diff --git a/src/test/run-pass/unsized2.rs b/src/test/run-pass/unsized2.rs index 5b9fa5230d..50d8d3d27f 100644 --- a/src/test/run-pass/unsized2.rs +++ b/src/test/run-pass/unsized2.rs @@ -89,7 +89,7 @@ trait T7 { fn m2(&self, x: &T5); } -// The last field in a struct or variant may be unsized +// The last field in a struct may be unsized struct S2 { f: X, } @@ -97,12 +97,6 @@ struct S3 { f1: isize, f2: X, } -enum E { - V1(X), - V2{x: X}, - V3(isize, X), - V4{u: isize, x: X}, -} pub fn main() { } diff --git a/src/test/run-pass/utf8_chars.rs b/src/test/run-pass/utf8_chars.rs index 0f75150129..0a984429fa 100644 --- a/src/test/run-pass/utf8_chars.rs +++ b/src/test/run-pass/utf8_chars.rs @@ -15,7 +15,7 @@ use std::str; pub fn main() { // Chars of 1, 2, 3, and 4 bytes - let chs: Vec = vec!('e', 'é', '€', '\u{10000}'); + let chs: Vec = vec!['e', 'é', '€', '\u{10000}']; let s: String = chs.iter().cloned().collect(); let schs: Vec = s.chars().collect(); diff --git a/src/test/run-pass/vec-concat.rs b/src/test/run-pass/vec-concat.rs index 5fe9dd6059..8ba8df57e5 100644 --- a/src/test/run-pass/vec-concat.rs +++ b/src/test/run-pass/vec-concat.rs @@ -11,8 +11,8 @@ use std::vec; pub fn main() { - let a: Vec = vec!(1, 2, 3, 4, 5); - let b: Vec = vec!(6, 7, 8, 9, 0); + let a: Vec = vec![1, 2, 3, 4, 5]; + let b: Vec = vec![6, 7, 8, 9, 0]; let mut v: Vec = a; v.extend_from_slice(&b); println!("{}", v[9]); diff --git a/src/test/run-pass/vec-growth.rs b/src/test/run-pass/vec-growth.rs index e51d898e1d..5bf6a457df 100644 --- a/src/test/run-pass/vec-growth.rs +++ b/src/test/run-pass/vec-growth.rs @@ -11,7 +11,7 @@ pub fn main() { - let mut v = vec!(1); + let mut v = vec![1]; v.push(2); v.push(3); v.push(4); diff --git a/src/test/run-pass/vec-late-init.rs b/src/test/run-pass/vec-late-init.rs index 7a8c0739ef..420f6a429f 100644 --- a/src/test/run-pass/vec-late-init.rs +++ b/src/test/run-pass/vec-late-init.rs @@ -11,6 +11,6 @@ pub fn main() { let mut later: Vec ; - if true { later = vec!(1); } else { later = vec!(2); } + if true { later = vec![1]; } else { later = vec![2]; } println!("{}", later[0]); } 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 35af249ef5..135ecb4749 100644 --- a/src/test/run-pass/vec-macro-with-trailing-comma.rs +++ b/src/test/run-pass/vec-macro-with-trailing-comma.rs @@ -11,6 +11,6 @@ pub fn main() { - assert_eq!(vec!(1), vec!(1,)); - assert_eq!(vec!(1, 2, 3), vec!(1, 2, 3,)); + assert_eq!(vec![1], vec![1,]); + assert_eq!(vec![1, 2, 3], vec![1, 2, 3,]); } diff --git a/src/test/run-pass/vec-matching.rs b/src/test/run-pass/vec-matching.rs index 97006f54cd..bd0731a555 100644 --- a/src/test/run-pass/vec-matching.rs +++ b/src/test/run-pass/vec-matching.rs @@ -144,6 +144,20 @@ fn e() { assert_eq!(c, 1); } +fn f() { + let x = &[1, 2, 3, 4, 5]; + let [a, [b, [c, ..].., d].., e] = *x; + assert_eq!((a, b, c, d, e), (1, 2, 3, 4, 5)); + + let x: &[isize] = x; + let (a, b, c, d, e) = match *x { + [a, [b, [c, ..].., d].., e] => (a, b, c, d, e), + _ => unimplemented!() + }; + + assert_eq!((a, b, c, d, e), (1, 2, 3, 4, 5)); +} + pub fn main() { a(); b(); @@ -151,4 +165,5 @@ pub fn main() { c(); d(); e(); + f(); } diff --git a/src/test/run-pass/vec-push.rs b/src/test/run-pass/vec-push.rs index 33f01c5bd4..14a52cc4b5 100644 --- a/src/test/run-pass/vec-push.rs +++ b/src/test/run-pass/vec-push.rs @@ -8,4 +8,4 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -pub fn main() { let mut v = vec!(1, 2, 3); v.push(1); } +pub fn main() { let mut v = vec![1, 2, 3]; v.push(1); } diff --git a/src/test/run-pass/vec-to_str.rs b/src/test/run-pass/vec-to_str.rs index f000ada770..1fed6a0be4 100644 --- a/src/test/run-pass/vec-to_str.rs +++ b/src/test/run-pass/vec-to_str.rs @@ -10,9 +10,9 @@ pub fn main() { - assert_eq!(format!("{:?}", vec!(0, 1)), "[0, 1]".to_string()); + assert_eq!(format!("{:?}", vec![0, 1]), "[0, 1]".to_string()); - let foo = vec!(3, 4); + let foo = vec![3, 4]; let bar: &[isize] = &[4, 5]; assert_eq!(format!("{:?}", foo), "[3, 4]"); diff --git a/src/test/run-pass/vec.rs b/src/test/run-pass/vec.rs index c61b3d56db..9cacb9db20 100644 --- a/src/test/run-pass/vec.rs +++ b/src/test/run-pass/vec.rs @@ -11,7 +11,7 @@ pub fn main() { - let v: Vec = vec!(10, 20); + let v: Vec = vec![10, 20]; assert_eq!(v[0], 10); assert_eq!(v[1], 20); let mut x: usize = 0; diff --git a/src/test/run-pass/while-with-break.rs b/src/test/run-pass/while-with-break.rs index ed149ad510..4c599e9c42 100644 --- a/src/test/run-pass/while-with-break.rs +++ b/src/test/run-pass/while-with-break.rs @@ -16,7 +16,7 @@ pub fn main() { i = i + 1; if i == 95 { let _v: Vec = - vec!(1, 2, 3, 4, 5); // we check that it is freed by break + vec![1, 2, 3, 4, 5]; // we check that it is freed by break println!("breaking"); break; diff --git a/src/test/rustdoc/line-breaks.rs b/src/test/rustdoc/line-breaks.rs new file mode 100644 index 0000000000..cc608a2447 --- /dev/null +++ b/src/test/rustdoc/line-breaks.rs @@ -0,0 +1,21 @@ +// Copyright 2016 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +#![crate_name = "foo"] + +//@count foo/fn.function_with_a_really_long_name.html //pre/br 2 +pub fn function_with_a_really_long_name(parameter_one: i32, + parameter_two: i32) + -> Option { + Some(parameter_one + parameter_two) +} + +//@count foo/fn.short_name.html //pre/br 0 +pub fn short_name(param: i32) -> i32 { param + 1 } diff --git a/src/test/rustdoc/playground-empty.rs b/src/test/rustdoc/playground-empty.rs new file mode 100644 index 0000000000..00881a62dd --- /dev/null +++ b/src/test/rustdoc/playground-empty.rs @@ -0,0 +1,21 @@ +// Copyright 2016 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +#![crate_name = "foo"] + +#![doc(html_playground_url = "")] + +//! module docs +//! +//! ``` +//! println!("Hello, world!"); +//! ``` + +// @!has foo/index.html '//a[@class="test-arrow"]' "Run" diff --git a/src/test/rustdoc/playground-none.rs b/src/test/rustdoc/playground-none.rs new file mode 100644 index 0000000000..83c312d7ab --- /dev/null +++ b/src/test/rustdoc/playground-none.rs @@ -0,0 +1,19 @@ +// Copyright 2016 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +#![crate_name = "foo"] + +//! module docs +//! +//! ``` +//! println!("Hello, world!"); +//! ``` + +// @!has foo/index.html '//a[@class="test-arrow"]' "Run" diff --git a/src/test/rustdoc/playground.rs b/src/test/rustdoc/playground.rs new file mode 100644 index 0000000000..9eb8dec51a --- /dev/null +++ b/src/test/rustdoc/playground.rs @@ -0,0 +1,39 @@ +// Copyright 2016 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +// ignore-tidy-linelength + +#![crate_name = "foo"] + +#![doc(html_playground_url = "https://www.example.com/")] + +//! module docs +//! +//! ``` +//! println!("Hello, world!"); +//! ``` +//! +//! ``` +//! fn main() { +//! println!("Hello, world!"); +//! } +//! ``` +//! +//! ``` +//! #![feature(something)] +//! +//! fn main() { +//! println!("Hello, world!"); +//! } +//! ``` + +// @matches foo/index.html '//a[@class="test-arrow"][@href="https://www.example.com/?code=fn%20main()%20%7B%0A%20%20%20%20println!(%22Hello%2C%20world!%22)%3B%0A%7D%0A"]' "Run" +// @matches foo/index.html '//a[@class="test-arrow"][@href="https://www.example.com/?code=fn%20main()%20%7B%0Aprintln!(%22Hello%2C%20world!%22)%3B%0A%7D"]' "Run" +// @matches foo/index.html '//a[@class="test-arrow"][@href="https://www.example.com/?code=%23!%5Bfeature(something)%5D%0A%0Afn%20main()%20%7B%0A%20%20%20%20println!(%22Hello%2C%20world!%22)%3B%0A%7D%0A&version=nightly"]' "Run" diff --git a/src/test/compile-fail-fulldeps/rustc-macro/auxiliary/derive-a-2.rs b/src/test/rustdoc/rustc-macro-crate.rs similarity index 68% rename from src/test/compile-fail-fulldeps/rustc-macro/auxiliary/derive-a-2.rs rename to src/test/rustdoc/rustc-macro-crate.rs index ff00a9d96a..fe80a90955 100644 --- a/src/test/compile-fail-fulldeps/rustc-macro/auxiliary/derive-a-2.rs +++ b/src/test/rustdoc/rustc-macro-crate.rs @@ -8,18 +8,17 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -// force-host // no-prefer-dynamic -#![feature(rustc_macro)] -#![feature(rustc_macro_lib)] -#![crate_type = "rustc-macro"] +#![feature(proc_macro)] +#![feature(proc_macro_lib)] +#![crate_type = "proc-macro"] -extern crate rustc_macro; +extern crate proc_macro; -use rustc_macro::TokenStream; +use proc_macro::TokenStream; -#[rustc_macro_derive(A)] -pub fn derive_a(input: TokenStream) -> TokenStream { +#[proc_macro_derive(Foo)] +pub fn foo(input: TokenStream) -> TokenStream { input } diff --git a/src/test/ui/check_match/issue-35609.rs b/src/test/ui/check_match/issue-35609.rs new file mode 100644 index 0000000000..6497f69035 --- /dev/null +++ b/src/test/ui/check_match/issue-35609.rs @@ -0,0 +1,53 @@ +// Copyright 2016 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +enum Enum { + A, B, C, D, E, F +} +use Enum::*; + +struct S(Enum, ()); +struct Sd { x: Enum, y: () } + +fn main() { + match (A, ()) { + (A, _) => {} + } + + match (A, A) { + (_, A) => {} + } + + match ((A, ()), ()) { + ((A, ()), _) => {} + } + + match ((A, ()), A) { + ((A, ()), _) => {} + } + + match ((A, ()), ()) { + ((A, _), _) => {} + } + + + match S(A, ()) { + S(A, _) => {} + } + + match (Sd { x: A, y: () }) { + Sd { x: A, y: _ } => {} + } + + match Some(A) { + Some(A) => (), + None => () + } +} diff --git a/src/test/ui/check_match/issue-35609.stderr b/src/test/ui/check_match/issue-35609.stderr new file mode 100644 index 0000000000..66069c7a86 --- /dev/null +++ b/src/test/ui/check_match/issue-35609.stderr @@ -0,0 +1,50 @@ +error[E0004]: non-exhaustive patterns: `(B, _)`, `(C, _)`, `(D, _)` and 2 more not covered + --> $DIR/issue-35609.rs:20:11 + | +20 | match (A, ()) { + | ^^^^^^^ patterns `(B, _)`, `(C, _)`, `(D, _)` and 2 more not covered + +error[E0004]: non-exhaustive patterns: `(A, B)`, `(B, B)`, `(C, B)` and 27 more not covered + --> $DIR/issue-35609.rs:24:11 + | +24 | match (A, A) { + | ^^^^^^ patterns `(A, B)`, `(B, B)`, `(C, B)` and 27 more not covered + +error[E0004]: non-exhaustive patterns: `((B, _), _)`, `((C, _), _)`, `((D, _), _)` and 2 more not covered + --> $DIR/issue-35609.rs:28:11 + | +28 | match ((A, ()), ()) { + | ^^^^^^^^^^^^^ patterns `((B, _), _)`, `((C, _), _)`, `((D, _), _)` and 2 more not covered + +error[E0004]: non-exhaustive patterns: `((B, _), _)`, `((C, _), _)`, `((D, _), _)` and 2 more not covered + --> $DIR/issue-35609.rs:32:11 + | +32 | match ((A, ()), A) { + | ^^^^^^^^^^^^ patterns `((B, _), _)`, `((C, _), _)`, `((D, _), _)` and 2 more not covered + +error[E0004]: non-exhaustive patterns: `((B, _), _)`, `((C, _), _)`, `((D, _), _)` and 2 more not covered + --> $DIR/issue-35609.rs:36:11 + | +36 | match ((A, ()), ()) { + | ^^^^^^^^^^^^^ patterns `((B, _), _)`, `((C, _), _)`, `((D, _), _)` and 2 more not covered + +error[E0004]: non-exhaustive patterns: `S(B, _)`, `S(C, _)`, `S(D, _)` and 2 more not covered + --> $DIR/issue-35609.rs:41:11 + | +41 | match S(A, ()) { + | ^^^^^^^^ patterns `S(B, _)`, `S(C, _)`, `S(D, _)` and 2 more not covered + +error[E0004]: non-exhaustive patterns: `Sd { x: B, .. }`, `Sd { x: C, .. }`, `Sd { x: D, .. }` and 2 more not covered + --> $DIR/issue-35609.rs:45:11 + | +45 | match (Sd { x: A, y: () }) { + | ^^^^^^^^^^^^^^^^^^^^ patterns `Sd { x: B, .. }`, `Sd { x: C, .. }`, `Sd { x: D, .. }` and 2 more not covered + +error[E0004]: non-exhaustive patterns: `Some(B)`, `Some(C)`, `Some(D)` and 2 more not covered + --> $DIR/issue-35609.rs:49:11 + | +49 | match Some(A) { + | ^^^^^^^ patterns `Some(B)`, `Some(C)`, `Some(D)` and 2 more not covered + +error: aborting due to 8 previous errors + diff --git a/src/test/ui/compare-method/proj-outlives-region.rs b/src/test/ui/compare-method/proj-outlives-region.rs new file mode 100644 index 0000000000..54cfe4be9c --- /dev/null +++ b/src/test/ui/compare-method/proj-outlives-region.rs @@ -0,0 +1,27 @@ +// Copyright 2016 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +#![allow(dead_code)] +#![deny(extra_requirement_in_impl)] + +// Test that we elaborate `Type: 'region` constraints and infer various important things. + +trait Master<'a, T: ?Sized, U> { + fn foo() where T: 'a; +} + +// `U::Item: 'a` does not imply that `U: 'a` +impl<'a, U: Iterator> Master<'a, U::Item, U> for () { + fn foo() where U: 'a { } //~ ERROR E0276 +} + +fn main() { + println!("Hello, world!"); +} diff --git a/src/test/ui/compare-method/proj-outlives-region.stderr b/src/test/ui/compare-method/proj-outlives-region.stderr new file mode 100644 index 0000000000..79293e0dee --- /dev/null +++ b/src/test/ui/compare-method/proj-outlives-region.stderr @@ -0,0 +1,19 @@ +error[E0276]: impl has stricter requirements than trait + --> $DIR/proj-outlives-region.rs:22:5 + | +17 | fn foo() where T: 'a; + | --------------------- definition of `foo` from trait +... +22 | fn foo() where U: 'a { } //~ ERROR E0276 + | ^^^^^^^^^^^^^^^^^^^^^^^^ impl has extra requirement `U: 'a` + | + = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! + = note: for more information, see issue #37166 +note: lint level defined here + --> $DIR/proj-outlives-region.rs:12:9 + | +12 | #![deny(extra_requirement_in_impl)] + | ^^^^^^^^^^^^^^^^^^^^^^^^^ + +error: aborting due to previous error + diff --git a/src/test/ui/compare-method/proj-outlives-region.stdout b/src/test/ui/compare-method/proj-outlives-region.stdout new file mode 100644 index 0000000000..e69de29bb2 diff --git a/src/test/compile-fail/region-bound-extra-bound-in-impl.rs b/src/test/ui/compare-method/region-extra-2.rs similarity index 94% rename from src/test/compile-fail/region-bound-extra-bound-in-impl.rs rename to src/test/ui/compare-method/region-extra-2.rs index 5bcc6be4c3..b0cd3b8fdd 100644 --- a/src/test/compile-fail/region-bound-extra-bound-in-impl.rs +++ b/src/test/ui/compare-method/region-extra-2.rs @@ -17,7 +17,7 @@ trait Tr<'a, T> { impl<'a, T> Tr<'a, T> for &'a mut [T] { fn renew<'b: 'a>(self) -> &'b mut [T] where 'a: 'b { - //~^ ERROR lifetime bound not satisfied + //~^ ERROR E0276 &mut self[..] } } diff --git a/src/test/ui/compare-method/region-extra-2.stderr b/src/test/ui/compare-method/region-extra-2.stderr new file mode 100644 index 0000000000..54a551bcfe --- /dev/null +++ b/src/test/ui/compare-method/region-extra-2.stderr @@ -0,0 +1,11 @@ +error[E0276]: impl has stricter requirements than trait + --> $DIR/region-extra-2.rs:19:5 + | +15 | fn renew<'b: 'a>(self) -> &'b mut [T]; + | -------------------------------------- definition of `renew` from trait +... +19 | fn renew<'b: 'a>(self) -> &'b mut [T] where 'a: 'b { + | ^ impl has extra requirement `'a: 'b` + +error: aborting due to previous error + diff --git a/src/test/ui/compare-method/region-extra.rs b/src/test/ui/compare-method/region-extra.rs new file mode 100644 index 0000000000..d61d025021 --- /dev/null +++ b/src/test/ui/compare-method/region-extra.rs @@ -0,0 +1,27 @@ +// Copyright 2016 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +#![allow(dead_code)] +#![deny(extra_requirement_in_impl)] + +// Test that you cannot add an extra where clause in the impl relating +// two regions. + +trait Master<'a, 'b> { + fn foo(); +} + +impl<'a, 'b> Master<'a, 'b> for () { + fn foo() where 'a: 'b { } +} + +fn main() { + println!("Hello, world!"); +} diff --git a/src/test/ui/compare-method/region-extra.stderr b/src/test/ui/compare-method/region-extra.stderr new file mode 100644 index 0000000000..e657813221 --- /dev/null +++ b/src/test/ui/compare-method/region-extra.stderr @@ -0,0 +1,11 @@ +error[E0276]: impl has stricter requirements than trait + --> $DIR/region-extra.rs:22:5 + | +18 | fn foo(); + | --------- definition of `foo` from trait +... +22 | fn foo() where 'a: 'b { } + | ^^^^^^^^^^^^^^^^^^^^^^^^^ impl has extra requirement `'a: 'b` + +error: aborting due to previous error + diff --git a/src/test/ui/compare-method/region-extra.stdout b/src/test/ui/compare-method/region-extra.stdout new file mode 100644 index 0000000000..e69de29bb2 diff --git a/src/test/ui/compare-method/region-unrelated.rs b/src/test/ui/compare-method/region-unrelated.rs new file mode 100644 index 0000000000..8f79b30bd5 --- /dev/null +++ b/src/test/ui/compare-method/region-unrelated.rs @@ -0,0 +1,28 @@ +// Copyright 2016 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +#![allow(dead_code)] +#![deny(extra_requirement_in_impl)] + +// Test that we elaborate `Type: 'region` constraints and infer various important things. + +trait Master<'a, T: ?Sized, U> { + fn foo() where T: 'a; +} + +// `U: 'a` does not imply `V: 'a` +impl<'a, U, V> Master<'a, U, V> for () { + fn foo() where V: 'a { } + //~^ ERROR parameter type `V` may not live long enough +} + +fn main() { + println!("Hello, world!"); +} diff --git a/src/test/ui/compare-method/region-unrelated.stderr b/src/test/ui/compare-method/region-unrelated.stderr new file mode 100644 index 0000000000..b7cfdf799b --- /dev/null +++ b/src/test/ui/compare-method/region-unrelated.stderr @@ -0,0 +1,19 @@ +error[E0276]: impl has stricter requirements than trait + --> $DIR/region-unrelated.rs:22:5 + | +17 | fn foo() where T: 'a; + | --------------------- definition of `foo` from trait +... +22 | fn foo() where V: 'a { } + | ^^^^^^^^^^^^^^^^^^^^^^^^ impl has extra requirement `V: 'a` + | + = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! + = note: for more information, see issue #37166 +note: lint level defined here + --> $DIR/region-unrelated.rs:12:9 + | +12 | #![deny(extra_requirement_in_impl)] + | ^^^^^^^^^^^^^^^^^^^^^^^^^ + +error: aborting due to previous error + diff --git a/src/test/ui/compare-method/region-unrelated.stdout b/src/test/ui/compare-method/region-unrelated.stdout new file mode 100644 index 0000000000..e69de29bb2 diff --git a/src/test/compile-fail/issue-2611-5.rs b/src/test/ui/compare-method/reordered-type-param.rs similarity index 98% rename from src/test/compile-fail/issue-2611-5.rs rename to src/test/ui/compare-method/reordered-type-param.rs index 440294f38a..0b844d4521 100644 --- a/src/test/compile-fail/issue-2611-5.rs +++ b/src/test/ui/compare-method/reordered-type-param.rs @@ -10,6 +10,8 @@ // Tests that ty params get matched correctly when comparing // an impl against a trait +// +// cc #26111 trait A { fn b(&self, x: C) -> C; diff --git a/src/test/ui/compare-method/reordered-type-param.stderr b/src/test/ui/compare-method/reordered-type-param.stderr new file mode 100644 index 0000000000..985b85cc4e --- /dev/null +++ b/src/test/ui/compare-method/reordered-type-param.stderr @@ -0,0 +1,14 @@ +error[E0053]: method `b` has an incompatible type for trait + --> $DIR/reordered-type-param.rs:26:30 + | +17 | fn b(&self, x: C) -> C; + | - type in trait +... +26 | fn b(&self, _x: G) -> G { panic!() } //~ ERROR method `b` has an incompatible type + | ^ expected type parameter, found a different type parameter + | + = note: expected type `fn(&E, F) -> F` + = note: found type `fn(&E, G) -> G` + +error: aborting due to previous error + diff --git a/src/test/compile-fail/issue-2611-4.rs b/src/test/ui/compare-method/trait-bound-on-type-parameter.rs similarity index 71% rename from src/test/compile-fail/issue-2611-4.rs rename to src/test/ui/compare-method/trait-bound-on-type-parameter.rs index 16d7ea4684..09e9fb4ca2 100644 --- a/src/test/compile-fail/issue-2611-4.rs +++ b/src/test/ui/compare-method/trait-bound-on-type-parameter.rs @@ -8,8 +8,10 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -// Tests that an impl method's bounds aren't *more* restrictive -// than the trait method it's implementing +// Tests that impl can't add extra `F: Sync` bound aren't *more* restrictive +// than the trait method it's implementing. +// +// Regr test for #26111. trait A { fn b(&self, x: C) -> C; @@ -20,8 +22,7 @@ struct E { } impl A for E { - fn b(&self, _x: F) -> F { panic!() } - //~^ ERROR `F: std::marker::Sync` appears on the impl method + fn b(&self, _x: F) -> F { panic!() } //~ ERROR E0276 } fn main() {} diff --git a/src/test/ui/compare-method/trait-bound-on-type-parameter.stderr b/src/test/ui/compare-method/trait-bound-on-type-parameter.stderr new file mode 100644 index 0000000000..7112a00c7b --- /dev/null +++ b/src/test/ui/compare-method/trait-bound-on-type-parameter.stderr @@ -0,0 +1,11 @@ +error[E0276]: impl has stricter requirements than trait + --> $DIR/trait-bound-on-type-parameter.rs:25:5 + | +17 | fn b(&self, x: C) -> C; + | ---------------------------- definition of `b` from trait +... +25 | fn b(&self, _x: F) -> F { panic!() } //~ ERROR E0276 + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ impl has extra requirement `F: std::marker::Sync` + +error: aborting due to previous error + diff --git a/src/test/compile-fail/trait-bounds-impl-comparison-1.rs b/src/test/ui/compare-method/traits-misc-mismatch-1.rs similarity index 82% rename from src/test/compile-fail/trait-bounds-impl-comparison-1.rs rename to src/test/ui/compare-method/traits-misc-mismatch-1.rs index 9cf65a9d00..cca282a1d1 100644 --- a/src/test/compile-fail/trait-bounds-impl-comparison-1.rs +++ b/src/test/ui/compare-method/traits-misc-mismatch-1.rs @@ -34,15 +34,15 @@ trait Foo { impl Foo for isize { // invalid bound for T, was defined as Eq in trait fn test_error1_fn(&self) {} - //~^ ERROR the requirement `T: std::cmp::Ord` appears on the impl + //~^ ERROR E0276 // invalid bound for T, was defined as Eq + Ord in trait fn test_error2_fn(&self) {} - //~^ ERROR the requirement `T: B` appears on the impl + //~^ ERROR E0276 // invalid bound for T, was defined as Eq + Ord in trait fn test_error3_fn(&self) {} - //~^ ERROR the requirement `T: B` appears on the impl + //~^ ERROR E0276 // multiple bounds, same order as in trait fn test3_fn(&self) {} @@ -52,16 +52,16 @@ impl Foo for isize { // parameters in impls must be equal or more general than in the defining trait fn test_error5_fn(&self) {} - //~^ ERROR the requirement `T: B` appears on the impl + //~^ ERROR E0276 // bound `std::cmp::Eq` not enforced by this implementation, but this is OK fn test6_fn(&self) {} fn test_error7_fn(&self) {} - //~^ ERROR the requirement `T: std::cmp::Eq` appears on the impl + //~^ ERROR E0276 fn test_error8_fn(&self) {} - //~^ ERROR the requirement `T: C` appears on the impl + //~^ ERROR E0276 } trait Getter { @@ -74,7 +74,7 @@ trait Trait { impl Trait for usize { fn method>(&self) {} - //~^ ERROR `G: Getter` appears on the impl method + //~^ ERROR E0276 } fn main() {} diff --git a/src/test/ui/compare-method/traits-misc-mismatch-1.stderr b/src/test/ui/compare-method/traits-misc-mismatch-1.stderr new file mode 100644 index 0000000000..f221ebe330 --- /dev/null +++ b/src/test/ui/compare-method/traits-misc-mismatch-1.stderr @@ -0,0 +1,65 @@ +error[E0276]: impl has stricter requirements than trait + --> $DIR/traits-misc-mismatch-1.rs:36:5 + | +23 | fn test_error1_fn(&self); + | -------------------------------- definition of `test_error1_fn` from trait +... +36 | fn test_error1_fn(&self) {} + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ impl has extra requirement `T: std::cmp::Ord` + +error[E0276]: impl has stricter requirements than trait + --> $DIR/traits-misc-mismatch-1.rs:40:5 + | +24 | fn test_error2_fn(&self); + | -------------------------------------- definition of `test_error2_fn` from trait +... +40 | fn test_error2_fn(&self) {} + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ impl has extra requirement `T: B` + +error[E0276]: impl has stricter requirements than trait + --> $DIR/traits-misc-mismatch-1.rs:44:5 + | +25 | fn test_error3_fn(&self); + | -------------------------------------- definition of `test_error3_fn` from trait +... +44 | fn test_error3_fn(&self) {} + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ impl has extra requirement `T: B` + +error[E0276]: impl has stricter requirements than trait + --> $DIR/traits-misc-mismatch-1.rs:54:5 + | +28 | fn test_error5_fn(&self); + | ------------------------------- definition of `test_error5_fn` from trait +... +54 | fn test_error5_fn(&self) {} + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ impl has extra requirement `T: B` + +error[E0276]: impl has stricter requirements than trait + --> $DIR/traits-misc-mismatch-1.rs:60:5 + | +30 | fn test_error7_fn(&self); + | ------------------------------- definition of `test_error7_fn` from trait +... +60 | fn test_error7_fn(&self) {} + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ impl has extra requirement `T: std::cmp::Eq` + +error[E0276]: impl has stricter requirements than trait + --> $DIR/traits-misc-mismatch-1.rs:63:5 + | +31 | fn test_error8_fn(&self); + | ------------------------------- definition of `test_error8_fn` from trait +... +63 | fn test_error8_fn(&self) {} + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ impl has extra requirement `T: C` + +error[E0276]: impl has stricter requirements than trait + --> $DIR/traits-misc-mismatch-1.rs:76:5 + | +72 | fn method>(&self); + | ---------------------------------- definition of `method` from trait +... +76 | fn method>(&self) {} + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ impl has extra requirement `G: Getter` + +error: aborting due to 7 previous errors + diff --git a/src/test/compile-fail/trait-bounds-impl-comparison-2.rs b/src/test/ui/compare-method/traits-misc-mismatch-2.rs similarity index 92% rename from src/test/compile-fail/trait-bounds-impl-comparison-2.rs rename to src/test/ui/compare-method/traits-misc-mismatch-2.rs index 8d587b29ba..e82cf256df 100644 --- a/src/test/compile-fail/trait-bounds-impl-comparison-2.rs +++ b/src/test/ui/compare-method/traits-misc-mismatch-2.rs @@ -21,7 +21,7 @@ trait IteratorUtil: Sized impl> IteratorUtil for T { fn zip>(self, other: U) -> ZipIterator { - //~^ ERROR the requirement `U: Iterator` appears on the impl method + //~^ ERROR E0276 ZipIterator{a: self, b: other} } } diff --git a/src/test/ui/compare-method/traits-misc-mismatch-2.stderr b/src/test/ui/compare-method/traits-misc-mismatch-2.stderr new file mode 100644 index 0000000000..5003550fd1 --- /dev/null +++ b/src/test/ui/compare-method/traits-misc-mismatch-2.stderr @@ -0,0 +1,11 @@ +error[E0276]: impl has stricter requirements than trait + --> $DIR/traits-misc-mismatch-2.rs:23:5 + | +19 | fn zip>(self, other: U) -> ZipIterator; + | ------------------------------------------------------------------ definition of `zip` from trait +... +23 | fn zip>(self, other: U) -> ZipIterator { + | ^ impl has extra requirement `U: Iterator` + +error: aborting due to previous error + diff --git a/src/test/ui/did_you_mean/issue-36798.rs b/src/test/ui/did_you_mean/issue-36798.rs new file mode 100644 index 0000000000..cd0d0951ab --- /dev/null +++ b/src/test/ui/did_you_mean/issue-36798.rs @@ -0,0 +1,18 @@ +// Copyright 2016 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +struct Foo { + bar: u8 +} + +fn main() { + let f = Foo { bar: 22 }; + f.baz; +} diff --git a/src/test/ui/did_you_mean/issue-36798.stderr b/src/test/ui/did_you_mean/issue-36798.stderr new file mode 100644 index 0000000000..c124747c80 --- /dev/null +++ b/src/test/ui/did_you_mean/issue-36798.stderr @@ -0,0 +1,8 @@ +error: no field `baz` on type `Foo` + --> $DIR/issue-36798.rs:17:7 + | +17 | f.baz; + | ^^^ did you mean `bar`? + +error: aborting due to previous error + diff --git a/src/test/ui/did_you_mean/issue-36798_unknown_field.rs b/src/test/ui/did_you_mean/issue-36798_unknown_field.rs new file mode 100644 index 0000000000..2970a325a6 --- /dev/null +++ b/src/test/ui/did_you_mean/issue-36798_unknown_field.rs @@ -0,0 +1,18 @@ +// Copyright 2016 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +struct Foo { + bar: u8 +} + +fn main() { + let f = Foo { bar: 22 }; + f.zz; +} diff --git a/src/test/ui/did_you_mean/issue-36798_unknown_field.stderr b/src/test/ui/did_you_mean/issue-36798_unknown_field.stderr new file mode 100644 index 0000000000..4e02f8bd0c --- /dev/null +++ b/src/test/ui/did_you_mean/issue-36798_unknown_field.stderr @@ -0,0 +1,8 @@ +error: no field `zz` on type `Foo` + --> $DIR/issue-36798_unknown_field.rs:17:7 + | +17 | f.zz; + | ^^ unknown field + +error: aborting due to previous error + diff --git a/src/test/ui/dropck/auxiliary/dropck_eyepatch_extern_crate.rs b/src/test/ui/dropck/auxiliary/dropck_eyepatch_extern_crate.rs new file mode 100644 index 0000000000..1b00d88dcb --- /dev/null +++ b/src/test/ui/dropck/auxiliary/dropck_eyepatch_extern_crate.rs @@ -0,0 +1,48 @@ +// Copyright 2016 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +#![feature(generic_param_attrs)] +#![feature(dropck_eyepatch)] + +// This is a support file for ../dropck-eyepatch-extern-crate.rs +// +// The point of this test is to illustrate that the `#[may_dangle]` +// attribute specifically allows, in the context of a type +// implementing `Drop`, a generic parameter to be instantiated with a +// lifetime that does not strictly outlive the owning type itself, +// and that this attribute's effects are preserved when importing +// the type from another crate. +// +// See also ../dropck-eyepatch.rs for more information about the general +// structure of the test. + +use std::fmt; + +pub struct Dt(pub &'static str, pub A); +pub struct Dr<'a, B:'a+fmt::Debug>(pub &'static str, pub &'a B); +pub struct Pt(pub &'static str, pub A, pub B); +pub struct Pr<'a, 'b, B:'a+'b+fmt::Debug>(pub &'static str, pub &'a B, pub &'b B); +pub struct St(pub &'static str, pub A); +pub struct Sr<'a, B:'a+fmt::Debug>(pub &'static str, pub &'a B); + +impl Drop for Dt { + fn drop(&mut self) { println!("drop {} {:?}", self.0, self.1); } +} +impl<'a, B: fmt::Debug> Drop for Dr<'a, B> { + fn drop(&mut self) { println!("drop {} {:?}", self.0, self.1); } +} +unsafe impl<#[may_dangle] A, B: fmt::Debug> Drop for Pt { + // (unsafe to access self.1 due to #[may_dangle] on A) + fn drop(&mut self) { println!("drop {} {:?}", self.0, self.2); } +} +unsafe impl<#[may_dangle] 'a, 'b, B: fmt::Debug> Drop for Pr<'a, 'b, B> { + // (unsafe to access self.1 due to #[may_dangle] on 'a) + fn drop(&mut self) { println!("drop {} {:?}", self.0, self.2); } +} diff --git a/src/test/ui/dropck/dropck-eyepatch-extern-crate.rs b/src/test/ui/dropck/dropck-eyepatch-extern-crate.rs new file mode 100644 index 0000000000..5e200dbdbf --- /dev/null +++ b/src/test/ui/dropck/dropck-eyepatch-extern-crate.rs @@ -0,0 +1,55 @@ +// Copyright 2016 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +// aux-build:dropck_eyepatch_extern_crate.rs + +// The point of this test is to illustrate that the `#[may_dangle]` +// attribute specifically allows, in the context of a type +// implementing `Drop`, a generic parameter to be instantiated with a +// lifetime that does not strictly outlive the owning type itself, +// and that this attribute's effects are preserved when importing +// the type from another crate. +// +// See also dropck-eyepatch.rs for more information about the general +// structure of the test. + +extern crate dropck_eyepatch_extern_crate as other; + +use other::{Dt,Dr,Pt,Pr,St,Sr}; + +fn main() { + use std::cell::Cell; + let c_long; + let (c, mut dt, mut dr, mut pt, mut pr, st, sr) + : (Cell<_>, Dt<_>, Dr<_>, Pt<_, _>, Pr<_>, St<_>, Sr<_>); + c_long = Cell::new(1); + c = Cell::new(1); + + // No error: sufficiently long-lived state can be referenced in dtors + dt = Dt("dt", &c_long); + dr = Dr("dr", &c_long); + // Error: destructor order imprecisely modelled + dt = Dt("dt", &c); //~ ERROR `c` does not live long enough + dr = Dr("dr", &c); //~ ERROR `c` does not live long enough + + // No error: Drop impl asserts .1 (A and &'a _) are not accessed + pt = Pt("pt", &c, &c_long); + pr = Pr("pr", &c, &c_long); + + // Error: Drop impl's assertion does not apply to `B` nor `&'b _` + pt = Pt("pt", &c_long, &c); //~ ERROR `c` does not live long enough + pr = Pr("pr", &c_long, &c); //~ ERROR `c` does not live long enough + + // No error: St and Sr have no destructor. + st = St("st", &c); + sr = Sr("sr", &c); + + println!("{:?}", (dt.0, dr.0, pt.0, pr.0, st.0, sr.0)); +} diff --git a/src/test/ui/dropck/dropck-eyepatch-extern-crate.stderr b/src/test/ui/dropck/dropck-eyepatch-extern-crate.stderr new file mode 100644 index 0000000000..2a4ba22ecc --- /dev/null +++ b/src/test/ui/dropck/dropck-eyepatch-extern-crate.stderr @@ -0,0 +1,46 @@ +error: `c` does not live long enough + --> $DIR/dropck-eyepatch-extern-crate.rs:55:1 + | +39 | dt = Dt("dt", &c); //~ ERROR `c` does not live long enough + | - borrow occurs here +... +55 | } + | ^ `c` dropped here while still borrowed + | + = note: values in a scope are dropped in the opposite order they are created + +error: `c` does not live long enough + --> $DIR/dropck-eyepatch-extern-crate.rs:55:1 + | +40 | dr = Dr("dr", &c); //~ ERROR `c` does not live long enough + | - borrow occurs here +... +55 | } + | ^ `c` dropped here while still borrowed + | + = note: values in a scope are dropped in the opposite order they are created + +error: `c` does not live long enough + --> $DIR/dropck-eyepatch-extern-crate.rs:55:1 + | +47 | pt = Pt("pt", &c_long, &c); //~ ERROR `c` does not live long enough + | - borrow occurs here +... +55 | } + | ^ `c` dropped here while still borrowed + | + = note: values in a scope are dropped in the opposite order they are created + +error: `c` does not live long enough + --> $DIR/dropck-eyepatch-extern-crate.rs:55:1 + | +48 | pr = Pr("pr", &c_long, &c); //~ ERROR `c` does not live long enough + | - borrow occurs here +... +55 | } + | ^ `c` dropped here while still borrowed + | + = note: values in a scope are dropped in the opposite order they are created + +error: aborting due to 4 previous errors + diff --git a/src/test/ui/dropck/dropck-eyepatch-implies-unsafe-impl.rs b/src/test/ui/dropck/dropck-eyepatch-implies-unsafe-impl.rs new file mode 100644 index 0000000000..f92c8703dc --- /dev/null +++ b/src/test/ui/dropck/dropck-eyepatch-implies-unsafe-impl.rs @@ -0,0 +1,46 @@ +// Copyright 2016 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +#![feature(generic_param_attrs)] +#![feature(dropck_eyepatch)] + +// This test ensures that a use of `#[may_dangle]` is rejected if +// it is not attached to an `unsafe impl`. + +use std::fmt; + +struct Dt(&'static str, A); +struct Dr<'a, B:'a+fmt::Debug>(&'static str, &'a B); +struct Pt(&'static str, A, B); +struct Pr<'a, 'b, B:'a+'b+fmt::Debug>(&'static str, &'a B, &'b B); +struct St(&'static str, A); +struct Sr<'a, B:'a+fmt::Debug>(&'static str, &'a B); + +impl Drop for Dt { + fn drop(&mut self) { println!("drop {} {:?}", self.0, self.1); } +} +impl<'a, B: fmt::Debug> Drop for Dr<'a, B> { + fn drop(&mut self) { println!("drop {} {:?}", self.0, self.1); } +} +impl<#[may_dangle] A, B: fmt::Debug> Drop for Pt { + //~^ ERROR requires an `unsafe impl` declaration due to `#[may_dangle]` attribute + + // (unsafe to access self.1 due to #[may_dangle] on A) + fn drop(&mut self) { println!("drop {} {:?}", self.0, self.2); } +} +impl<#[may_dangle] 'a, 'b, B: fmt::Debug> Drop for Pr<'a, 'b, B> { + //~^ ERROR requires an `unsafe impl` declaration due to `#[may_dangle]` attribute + + // (unsafe to access self.1 due to #[may_dangle] on 'a) + fn drop(&mut self) { println!("drop {} {:?}", self.0, self.2); } +} + +fn main() { +} diff --git a/src/test/ui/dropck/dropck-eyepatch-implies-unsafe-impl.stderr b/src/test/ui/dropck/dropck-eyepatch-implies-unsafe-impl.stderr new file mode 100644 index 0000000000..c53cf020a9 --- /dev/null +++ b/src/test/ui/dropck/dropck-eyepatch-implies-unsafe-impl.stderr @@ -0,0 +1,14 @@ +error[E0569]: requires an `unsafe impl` declaration due to `#[may_dangle]` attribute + --> $DIR/dropck-eyepatch-implies-unsafe-impl.rs:32:1 + | +32 | impl<#[may_dangle] A, B: fmt::Debug> Drop for Pt { + | ^ + +error[E0569]: requires an `unsafe impl` declaration due to `#[may_dangle]` attribute + --> $DIR/dropck-eyepatch-implies-unsafe-impl.rs:38:1 + | +38 | impl<#[may_dangle] 'a, 'b, B: fmt::Debug> Drop for Pr<'a, 'b, B> { + | ^ + +error: aborting due to 2 previous errors + diff --git a/src/test/ui/dropck/dropck-eyepatch-reorder.rs b/src/test/ui/dropck/dropck-eyepatch-reorder.rs new file mode 100644 index 0000000000..68b0ff3b5f --- /dev/null +++ b/src/test/ui/dropck/dropck-eyepatch-reorder.rs @@ -0,0 +1,73 @@ +// Copyright 2016 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +#![feature(generic_param_attrs)] +#![feature(dropck_eyepatch)] + +// The point of this test is to test uses of `#[may_dangle]` attribute +// where the formal declaration order (in the impl generics) does not +// match the actual usage order (in the type instantiation). +// +// See also dropck-eyepatch.rs for more information about the general +// structure of the test. + +use std::fmt; + +struct Dt(&'static str, A); +struct Dr<'a, B:'a+fmt::Debug>(&'static str, &'a B); +struct Pt(&'static str, A, B); +struct Pr<'a, 'b, B:'a+'b+fmt::Debug>(&'static str, &'a B, &'b B); +struct St(&'static str, A); +struct Sr<'a, B:'a+fmt::Debug>(&'static str, &'a B); + +impl Drop for Dt { + fn drop(&mut self) { println!("drop {} {:?}", self.0, self.1); } +} +impl<'a, B: fmt::Debug> Drop for Dr<'a, B> { + fn drop(&mut self) { println!("drop {} {:?}", self.0, self.1); } +} +unsafe impl Drop for Pt { + // (unsafe to access self.1 due to #[may_dangle] on A) + fn drop(&mut self) { println!("drop {} {:?}", self.0, self.2); } +} +unsafe impl<'b, #[may_dangle] 'a, B: fmt::Debug> Drop for Pr<'a, 'b, B> { + // (unsafe to access self.1 due to #[may_dangle] on 'a) + fn drop(&mut self) { println!("drop {} {:?}", self.0, self.2); } +} + +fn main() { + use std::cell::Cell; + let c_long; + let (c, mut dt, mut dr, mut pt, mut pr, st, sr) + : (Cell<_>, Dt<_>, Dr<_>, Pt<_, _>, Pr<_>, St<_>, Sr<_>); + c_long = Cell::new(1); + c = Cell::new(1); + + // No error: sufficiently long-lived state can be referenced in dtors + dt = Dt("dt", &c_long); + dr = Dr("dr", &c_long); + // Error: destructor order imprecisely modelled + dt = Dt("dt", &c); //~ ERROR `c` does not live long enough + dr = Dr("dr", &c); //~ ERROR `c` does not live long enough + + // No error: Drop impl asserts .1 (A and &'a _) are not accessed + pt = Pt("pt", &c, &c_long); + pr = Pr("pr", &c, &c_long); + + // Error: Drop impl's assertion does not apply to `B` nor `&'b _` + pt = Pt("pt", &c_long, &c); //~ ERROR `c` does not live long enough + pr = Pr("pr", &c_long, &c); //~ ERROR `c` does not live long enough + + // No error: St and Sr have no destructor. + st = St("st", &c); + sr = Sr("sr", &c); + + println!("{:?}", (dt.0, dr.0, pt.0, pr.0, st.0, sr.0)); +} diff --git a/src/test/ui/dropck/dropck-eyepatch-reorder.stderr b/src/test/ui/dropck/dropck-eyepatch-reorder.stderr new file mode 100644 index 0000000000..cfcf988f31 --- /dev/null +++ b/src/test/ui/dropck/dropck-eyepatch-reorder.stderr @@ -0,0 +1,46 @@ +error: `c` does not live long enough + --> $DIR/dropck-eyepatch-reorder.rs:73:1 + | +57 | dt = Dt("dt", &c); //~ ERROR `c` does not live long enough + | - borrow occurs here +... +73 | } + | ^ `c` dropped here while still borrowed + | + = note: values in a scope are dropped in the opposite order they are created + +error: `c` does not live long enough + --> $DIR/dropck-eyepatch-reorder.rs:73:1 + | +58 | dr = Dr("dr", &c); //~ ERROR `c` does not live long enough + | - borrow occurs here +... +73 | } + | ^ `c` dropped here while still borrowed + | + = note: values in a scope are dropped in the opposite order they are created + +error: `c` does not live long enough + --> $DIR/dropck-eyepatch-reorder.rs:73:1 + | +65 | pt = Pt("pt", &c_long, &c); //~ ERROR `c` does not live long enough + | - borrow occurs here +... +73 | } + | ^ `c` dropped here while still borrowed + | + = note: values in a scope are dropped in the opposite order they are created + +error: `c` does not live long enough + --> $DIR/dropck-eyepatch-reorder.rs:73:1 + | +66 | pr = Pr("pr", &c_long, &c); //~ ERROR `c` does not live long enough + | - borrow occurs here +... +73 | } + | ^ `c` dropped here while still borrowed + | + = note: values in a scope are dropped in the opposite order they are created + +error: aborting due to 4 previous errors + diff --git a/src/test/ui/dropck/dropck-eyepatch.rs b/src/test/ui/dropck/dropck-eyepatch.rs new file mode 100644 index 0000000000..e442fade19 --- /dev/null +++ b/src/test/ui/dropck/dropck-eyepatch.rs @@ -0,0 +1,96 @@ +// Copyright 2016 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +#![feature(generic_param_attrs)] +#![feature(dropck_eyepatch)] + +// The point of this test is to illustrate that the `#[may_dangle]` +// attribute specifically allows, in the context of a type +// implementing `Drop`, a generic parameter to be instantiated with a +// lifetime that does not strictly outlive the owning type itself. +// +// Here we test that only the expected errors are issued. +// +// The illustration is made concrete by comparison with two variations +// on the type with `#[may_dangle]`: +// +// 1. an analogous type that does not implement `Drop` (and thus +// should exhibit maximal flexibility with respect to dropck), and +// +// 2. an analogous type that does not use `#[may_dangle]` (and thus +// should exhibit the standard limitations imposed by dropck. +// +// The types in this file follow a pattern, {D,P,S}{t,r}, where: +// +// - D means "I implement Drop" +// +// - P means "I implement Drop but guarantee my (first) parameter is +// pure, i.e. not accessed from the destructor"; no other parameters +// are pure. +// +// - S means "I do not implement Drop" +// +// - t suffix is used when the first generic is a type +// +// - r suffix is used when the first generic is a lifetime. + +use std::fmt; + +struct Dt(&'static str, A); +struct Dr<'a, B:'a+fmt::Debug>(&'static str, &'a B); +struct Pt(&'static str, A, B); +struct Pr<'a, 'b, B:'a+'b+fmt::Debug>(&'static str, &'a B, &'b B); +struct St(&'static str, A); +struct Sr<'a, B:'a+fmt::Debug>(&'static str, &'a B); + +impl Drop for Dt { + fn drop(&mut self) { println!("drop {} {:?}", self.0, self.1); } +} +impl<'a, B: fmt::Debug> Drop for Dr<'a, B> { + fn drop(&mut self) { println!("drop {} {:?}", self.0, self.1); } +} +unsafe impl<#[may_dangle] A, B: fmt::Debug> Drop for Pt { + // (unsafe to access self.1 due to #[may_dangle] on A) + fn drop(&mut self) { println!("drop {} {:?}", self.0, self.2); } +} +unsafe impl<#[may_dangle] 'a, 'b, B: fmt::Debug> Drop for Pr<'a, 'b, B> { + // (unsafe to access self.1 due to #[may_dangle] on 'a) + fn drop(&mut self) { println!("drop {} {:?}", self.0, self.2); } +} + +fn main() { + use std::cell::Cell; + let c_long; + let (c, mut dt, mut dr, mut pt, mut pr, st, sr) + : (Cell<_>, Dt<_>, Dr<_>, Pt<_, _>, Pr<_>, St<_>, Sr<_>); + c_long = Cell::new(1); + c = Cell::new(1); + + // No error: sufficiently long-lived state can be referenced in dtors + dt = Dt("dt", &c_long); + dr = Dr("dr", &c_long); + // Error: destructor order imprecisely modelled + dt = Dt("dt", &c); //~ ERROR `c` does not live long enough + dr = Dr("dr", &c); //~ ERROR `c` does not live long enough + + // No error: Drop impl asserts .1 (A and &'a _) are not accessed + pt = Pt("pt", &c, &c_long); + pr = Pr("pr", &c, &c_long); + + // Error: Drop impl's assertion does not apply to `B` nor `&'b _` + pt = Pt("pt", &c_long, &c); //~ ERROR `c` does not live long enough + pr = Pr("pr", &c_long, &c); //~ ERROR `c` does not live long enough + + // No error: St and Sr have no destructor. + st = St("st", &c); + sr = Sr("sr", &c); + + println!("{:?}", (dt.0, dr.0, pt.0, pr.0, st.0, sr.0)); +} diff --git a/src/test/ui/dropck/dropck-eyepatch.stderr b/src/test/ui/dropck/dropck-eyepatch.stderr new file mode 100644 index 0000000000..cd420756b4 --- /dev/null +++ b/src/test/ui/dropck/dropck-eyepatch.stderr @@ -0,0 +1,46 @@ +error: `c` does not live long enough + --> $DIR/dropck-eyepatch.rs:96:1 + | +80 | dt = Dt("dt", &c); //~ ERROR `c` does not live long enough + | - borrow occurs here +... +96 | } + | ^ `c` dropped here while still borrowed + | + = note: values in a scope are dropped in the opposite order they are created + +error: `c` does not live long enough + --> $DIR/dropck-eyepatch.rs:96:1 + | +81 | dr = Dr("dr", &c); //~ ERROR `c` does not live long enough + | - borrow occurs here +... +96 | } + | ^ `c` dropped here while still borrowed + | + = note: values in a scope are dropped in the opposite order they are created + +error: `c` does not live long enough + --> $DIR/dropck-eyepatch.rs:96:1 + | +88 | pt = Pt("pt", &c_long, &c); //~ ERROR `c` does not live long enough + | - borrow occurs here +... +96 | } + | ^ `c` dropped here while still borrowed + | + = note: values in a scope are dropped in the opposite order they are created + +error: `c` does not live long enough + --> $DIR/dropck-eyepatch.rs:96:1 + | +89 | pr = Pr("pr", &c_long, &c); //~ ERROR `c` does not live long enough + | - borrow occurs here +... +96 | } + | ^ `c` dropped here while still borrowed + | + = note: values in a scope are dropped in the opposite order they are created + +error: aborting due to 4 previous errors + diff --git a/src/test/ui/macros/macro-backtrace-invalid-internals.stderr b/src/test/ui/macros/macro-backtrace-invalid-internals.stderr index 82000a59bf..48f9bac906 100644 --- a/src/test/ui/macros/macro-backtrace-invalid-internals.stderr +++ b/src/test/ui/macros/macro-backtrace-invalid-internals.stderr @@ -7,11 +7,11 @@ error: no method named `fake` found for type `{integer}` in the current scope 50 | fake_method_stmt!(); | -------------------- in this macro invocation -error: attempted access of field `fake` on type `{integer}`, but no field with that name was found - --> $DIR/macro-backtrace-invalid-internals.rs:21:11 +error: no field `fake` on type `{integer}` + --> $DIR/macro-backtrace-invalid-internals.rs:21:13 | 21 | 1.fake - | ^^^^^^ + | ^^^^ ... 51 | fake_field_stmt!(); | ------------------- in this macro invocation @@ -34,11 +34,11 @@ error: no method named `fake` found for type `{integer}` in the current scope 54 | let _ = fake_method_expr!(); | ------------------- in this macro invocation -error: attempted access of field `fake` on type `{integer}`, but no field with that name was found - --> $DIR/macro-backtrace-invalid-internals.rs:39:11 +error: no field `fake` on type `{integer}` + --> $DIR/macro-backtrace-invalid-internals.rs:39:13 | 39 | 1.fake - | ^^^^^^ + | ^^^^ ... 55 | let _ = fake_field_expr!(); | ------------------ in this macro invocation diff --git a/src/test/ui/span/E0057.rs b/src/test/ui/span/E0057.rs new file mode 100644 index 0000000000..1fb5498b09 --- /dev/null +++ b/src/test/ui/span/E0057.rs @@ -0,0 +1,16 @@ +// Copyright 2016 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +fn main() { + let f = |x| x * 3; + let a = f(); //~ ERROR E0057 + let b = f(4); + let c = f(2, 3); //~ ERROR E0057 +} diff --git a/src/test/ui/span/E0057.stderr b/src/test/ui/span/E0057.stderr new file mode 100644 index 0000000000..656fdbe2b2 --- /dev/null +++ b/src/test/ui/span/E0057.stderr @@ -0,0 +1,18 @@ +error[E0057]: this function takes 1 parameter but 0 parameters were supplied + --> $DIR/E0057.rs:13:13 + | +13 | let a = f(); //~ ERROR E0057 + | ^^^ + | + = note: the following parameter type was expected: (_,) + +error[E0057]: this function takes 1 parameter but 2 parameters were supplied + --> $DIR/E0057.rs:15:15 + | +15 | let c = f(2, 3); //~ ERROR E0057 + | ^^^^ + | + = note: the following parameter type was expected: (_,) + +error: aborting due to 2 previous errors + diff --git a/src/test/compile-fail/borrowck/borrowck-let-suggestion-suffixes.rs b/src/test/ui/span/borrowck-let-suggestion-suffixes.rs similarity index 89% rename from src/test/compile-fail/borrowck/borrowck-let-suggestion-suffixes.rs rename to src/test/ui/span/borrowck-let-suggestion-suffixes.rs index 95c74348e7..1206d71667 100644 --- a/src/test/compile-fail/borrowck/borrowck-let-suggestion-suffixes.rs +++ b/src/test/ui/span/borrowck-let-suggestion-suffixes.rs @@ -17,9 +17,7 @@ fn f() { let young = ['y']; // statement 3 v2.push(&young[0]); // statement 4 - //~^ ERROR `young[..]` does not live long enough - //~| NOTE does not live long enough - //~| NOTE values in a scope are dropped in the opposite order they are created + //~^ NOTE borrow occurs here let mut v3 = Vec::new(); // statement 5 @@ -52,7 +50,9 @@ fn f() { v1.push(&old[0]); } -//~^ NOTE borrowed value dropped before borrower +//~^ ERROR `young[..]` does not live long enough +//~| NOTE `young[..]` dropped here while still borrowed +//~| NOTE values in a scope are dropped in the opposite order they are created //~| NOTE temporary value needs to live until here //~| NOTE temporary value needs to live until here diff --git a/src/test/ui/span/borrowck-let-suggestion-suffixes.stderr b/src/test/ui/span/borrowck-let-suggestion-suffixes.stderr new file mode 100644 index 0000000000..0bba986e43 --- /dev/null +++ b/src/test/ui/span/borrowck-let-suggestion-suffixes.stderr @@ -0,0 +1,52 @@ +error: `young[..]` does not live long enough + --> $DIR/borrowck-let-suggestion-suffixes.rs:52:1 + | +19 | v2.push(&young[0]); // statement 4 + | -------- borrow occurs here +... +52 | } + | ^ `young[..]` dropped here while still borrowed + | + = note: values in a scope are dropped in the opposite order they are created + +error: borrowed value does not live long enough + --> $DIR/borrowck-let-suggestion-suffixes.rs:24:14 + | +24 | v3.push(&'x'); // statement 6 + | ^^^ - temporary value only lives until here + | | + | temporary value created here +... +52 | } + | - temporary value needs to live until here + | + = note: consider using a `let` binding to increase its lifetime + +error: borrowed value does not live long enough + --> $DIR/borrowck-let-suggestion-suffixes.rs:34:18 + | +34 | v4.push(&'y'); + | ^^^ - temporary value only lives until here + | | + | temporary value created here +... +40 | } // (statement 7) + | - temporary value needs to live until here + | + = note: consider using a `let` binding to increase its lifetime + +error: borrowed value does not live long enough + --> $DIR/borrowck-let-suggestion-suffixes.rs:45:14 + | +45 | v5.push(&'z'); + | ^^^ - temporary value only lives until here + | | + | temporary value created here +... +52 | } + | - temporary value needs to live until here + | + = note: consider using a `let` binding to increase its lifetime + +error: aborting due to 4 previous errors + diff --git a/src/test/compile-fail/borrowck/borrowck-ref-into-rvalue.rs b/src/test/ui/span/borrowck-ref-into-rvalue.rs similarity index 100% rename from src/test/compile-fail/borrowck/borrowck-ref-into-rvalue.rs rename to src/test/ui/span/borrowck-ref-into-rvalue.rs diff --git a/src/test/ui/span/borrowck-ref-into-rvalue.stderr b/src/test/ui/span/borrowck-ref-into-rvalue.stderr new file mode 100644 index 0000000000..adbf39b3f7 --- /dev/null +++ b/src/test/ui/span/borrowck-ref-into-rvalue.stderr @@ -0,0 +1,16 @@ +error: borrowed value does not live long enough + --> $DIR/borrowck-ref-into-rvalue.rs:18:5 + | +14 | Some(ref m) => { //~ ERROR borrowed value does not live long enough + | ----- borrow occurs here +... +18 | } + | ^ borrowed value dropped here while still borrowed +19 | println!("{}", *msg); +20 | } + | - borrowed value needs to live until here + | + = note: consider using a `let` binding to increase its lifetime + +error: aborting due to previous error + diff --git a/src/test/compile-fail/destructor-restrictions.rs b/src/test/ui/span/destructor-restrictions.rs similarity index 100% rename from src/test/compile-fail/destructor-restrictions.rs rename to src/test/ui/span/destructor-restrictions.rs diff --git a/src/test/ui/span/destructor-restrictions.stderr b/src/test/ui/span/destructor-restrictions.stderr new file mode 100644 index 0000000000..3253212c5b --- /dev/null +++ b/src/test/ui/span/destructor-restrictions.stderr @@ -0,0 +1,12 @@ +error: `*a` does not live long enough + --> $DIR/destructor-restrictions.rs:19:5 + | +18 | *a.borrow() + 1 //~ ERROR `*a` does not live long enough + | - borrow occurs here +19 | }; + | ^- borrowed value needs to live until here + | | + | `*a` dropped here while still borrowed + +error: aborting due to previous error + diff --git a/src/test/compile-fail/dropck-object-cycle.rs b/src/test/ui/span/dropck-object-cycle.rs similarity index 89% rename from src/test/compile-fail/dropck-object-cycle.rs rename to src/test/ui/span/dropck-object-cycle.rs index 5432cbf402..ce9bc17432 100644 --- a/src/test/compile-fail/dropck-object-cycle.rs +++ b/src/test/ui/span/dropck-object-cycle.rs @@ -35,7 +35,7 @@ impl<'t> MakerTrait for Box+'static> { pub fn main() { let m : Box = make_val(); assert_eq!(object_invoke1(&*m), (4,5)); - //~^ ERROR `*m` does not live long enough + //~^ NOTE borrow occurs here // the problem here is that the full type of `m` is // @@ -55,3 +55,7 @@ pub fn main() { // the type of `m` *strictly outlives* `'m`. Hence we get an // error. } +//~^ ERROR `*m` does not live long enough +//~| NOTE `*m` dropped here while still borrowed +//~| NOTE values in a scope are dropped in the opposite order they are created + diff --git a/src/test/ui/span/dropck-object-cycle.stderr b/src/test/ui/span/dropck-object-cycle.stderr new file mode 100644 index 0000000000..e31c36e83d --- /dev/null +++ b/src/test/ui/span/dropck-object-cycle.stderr @@ -0,0 +1,13 @@ +error: `*m` does not live long enough + --> $DIR/dropck-object-cycle.rs:57:1 + | +37 | assert_eq!(object_invoke1(&*m), (4,5)); + | -- borrow occurs here +... +57 | } + | ^ `*m` dropped here while still borrowed + | + = note: values in a scope are dropped in the opposite order they are created + +error: aborting due to previous error + diff --git a/src/test/compile-fail/dropck_arr_cycle_checked.rs b/src/test/ui/span/dropck_arr_cycle_checked.rs similarity index 84% rename from src/test/compile-fail/dropck_arr_cycle_checked.rs rename to src/test/ui/span/dropck_arr_cycle_checked.rs index 9cfeaca6df..8e8b3c24c7 100644 --- a/src/test/compile-fail/dropck_arr_cycle_checked.rs +++ b/src/test/ui/span/dropck_arr_cycle_checked.rs @@ -100,13 +100,19 @@ fn f() { b1 = B::new(); b2 = B::new(); b3 = B::new(); - b1.a[0].v.set(Some(&b2)); //~ ERROR `b2` does not live long enough - b1.a[1].v.set(Some(&b3)); //~ ERROR `b3` does not live long enough - b2.a[0].v.set(Some(&b2)); //~ ERROR `b2` does not live long enough - b2.a[1].v.set(Some(&b3)); //~ ERROR `b3` does not live long enough - b3.a[0].v.set(Some(&b1)); //~ ERROR `b1` does not live long enough - b3.a[1].v.set(Some(&b2)); //~ ERROR `b2` does not live long enough + b1.a[0].v.set(Some(&b2)); + b1.a[1].v.set(Some(&b3)); + b2.a[0].v.set(Some(&b2)); + b2.a[1].v.set(Some(&b3)); + b3.a[0].v.set(Some(&b1)); + b3.a[1].v.set(Some(&b2)); } +//~^ ERROR `b2` does not live long enough +//~| ERROR `b3` does not live long enough +//~| ERROR `b2` does not live long enough +//~| ERROR `b3` does not live long enough +//~| ERROR `b1` does not live long enough +//~| ERROR `b2` does not live long enough fn main() { f(); diff --git a/src/test/ui/span/dropck_arr_cycle_checked.stderr b/src/test/ui/span/dropck_arr_cycle_checked.stderr new file mode 100644 index 0000000000..c89da0baef --- /dev/null +++ b/src/test/ui/span/dropck_arr_cycle_checked.stderr @@ -0,0 +1,67 @@ +error: `b2` does not live long enough + --> $DIR/dropck_arr_cycle_checked.rs:109:1 + | +103 | b1.a[0].v.set(Some(&b2)); + | -- borrow occurs here +... +109 | } + | ^ `b2` dropped here while still borrowed + | + = note: values in a scope are dropped in the opposite order they are created + +error: `b3` does not live long enough + --> $DIR/dropck_arr_cycle_checked.rs:109:1 + | +104 | b1.a[1].v.set(Some(&b3)); + | -- borrow occurs here +... +109 | } + | ^ `b3` dropped here while still borrowed + | + = note: values in a scope are dropped in the opposite order they are created + +error: `b2` does not live long enough + --> $DIR/dropck_arr_cycle_checked.rs:109:1 + | +105 | b2.a[0].v.set(Some(&b2)); + | -- borrow occurs here +... +109 | } + | ^ `b2` dropped here while still borrowed + | + = note: values in a scope are dropped in the opposite order they are created + +error: `b3` does not live long enough + --> $DIR/dropck_arr_cycle_checked.rs:109:1 + | +106 | b2.a[1].v.set(Some(&b3)); + | -- borrow occurs here +... +109 | } + | ^ `b3` dropped here while still borrowed + | + = note: values in a scope are dropped in the opposite order they are created + +error: `b1` does not live long enough + --> $DIR/dropck_arr_cycle_checked.rs:109:1 + | +107 | b3.a[0].v.set(Some(&b1)); + | -- borrow occurs here +108 | b3.a[1].v.set(Some(&b2)); +109 | } + | ^ `b1` dropped here while still borrowed + | + = note: values in a scope are dropped in the opposite order they are created + +error: `b2` does not live long enough + --> $DIR/dropck_arr_cycle_checked.rs:109:1 + | +108 | b3.a[1].v.set(Some(&b2)); + | -- borrow occurs here +109 | } + | ^ `b2` dropped here while still borrowed + | + = note: values in a scope are dropped in the opposite order they are created + +error: aborting due to 6 previous errors + diff --git a/src/test/compile-fail/dropck_direct_cycle_with_drop.rs b/src/test/ui/span/dropck_direct_cycle_with_drop.rs similarity index 92% rename from src/test/compile-fail/dropck_direct_cycle_with_drop.rs rename to src/test/ui/span/dropck_direct_cycle_with_drop.rs index 5db2372125..6d13dfc7a7 100644 --- a/src/test/compile-fail/dropck_direct_cycle_with_drop.rs +++ b/src/test/ui/span/dropck_direct_cycle_with_drop.rs @@ -43,9 +43,11 @@ impl<'a> Drop for D<'a> { fn g() { let (d1, d2) = (D::new(format!("d1")), D::new(format!("d2"))); - d1.p.set(Some(&d2)); //~ ERROR `d2` does not live long enough - d2.p.set(Some(&d1)); //~ ERROR `d1` does not live long enough + d1.p.set(Some(&d2)); + d2.p.set(Some(&d1)); } +//~^ ERROR `d2` does not live long enough +//~| ERROR `d1` does not live long enough fn main() { g(); diff --git a/src/test/ui/span/dropck_direct_cycle_with_drop.stderr b/src/test/ui/span/dropck_direct_cycle_with_drop.stderr new file mode 100644 index 0000000000..9eb2a21577 --- /dev/null +++ b/src/test/ui/span/dropck_direct_cycle_with_drop.stderr @@ -0,0 +1,23 @@ +error: `d2` does not live long enough + --> $DIR/dropck_direct_cycle_with_drop.rs:48:1 + | +46 | d1.p.set(Some(&d2)); + | -- borrow occurs here +47 | d2.p.set(Some(&d1)); +48 | } + | ^ `d2` dropped here while still borrowed + | + = note: values in a scope are dropped in the opposite order they are created + +error: `d1` does not live long enough + --> $DIR/dropck_direct_cycle_with_drop.rs:48:1 + | +47 | d2.p.set(Some(&d1)); + | -- borrow occurs here +48 | } + | ^ `d1` dropped here while still borrowed + | + = note: values in a scope are dropped in the opposite order they are created + +error: aborting due to 2 previous errors + diff --git a/src/test/compile-fail/dropck_misc_variants.rs b/src/test/ui/span/dropck_misc_variants.rs similarity index 92% rename from src/test/compile-fail/dropck_misc_variants.rs rename to src/test/ui/span/dropck_misc_variants.rs index ee957f20d0..7b94eb10df 100644 --- a/src/test/compile-fail/dropck_misc_variants.rs +++ b/src/test/ui/span/dropck_misc_variants.rs @@ -31,17 +31,17 @@ fn projection() { let (_w, bomb); bomb = vec![""]; _w = Wrap::<&[&str]>(NoisyDrop(&bomb)); - //~^ ERROR `bomb` does not live long enough } +//~^ ERROR `bomb` does not live long enough fn closure() { let (_w,v); v = vec![""]; _w = { let u = NoisyDrop(&v); - //~^ ERROR `v` does not live long enough move || u.0.len() }; } +//~^ ERROR `v` does not live long enough fn main() { closure(); projection() } diff --git a/src/test/ui/span/dropck_misc_variants.stderr b/src/test/ui/span/dropck_misc_variants.stderr new file mode 100644 index 0000000000..98c1cbbba7 --- /dev/null +++ b/src/test/ui/span/dropck_misc_variants.stderr @@ -0,0 +1,23 @@ +error: `bomb` does not live long enough + --> $DIR/dropck_misc_variants.rs:34:1 + | +33 | _w = Wrap::<&[&str]>(NoisyDrop(&bomb)); + | ---- borrow occurs here +34 | } + | ^ `bomb` dropped here while still borrowed + | + = note: values in a scope are dropped in the opposite order they are created + +error: `v` does not live long enough + --> $DIR/dropck_misc_variants.rs:44:1 + | +41 | let u = NoisyDrop(&v); + | - borrow occurs here +... +44 | } + | ^ `v` dropped here while still borrowed + | + = note: values in a scope are dropped in the opposite order they are created + +error: aborting due to 2 previous errors + diff --git a/src/test/compile-fail/dropck_vec_cycle_checked.rs b/src/test/ui/span/dropck_vec_cycle_checked.rs similarity index 85% rename from src/test/compile-fail/dropck_vec_cycle_checked.rs rename to src/test/ui/span/dropck_vec_cycle_checked.rs index caf25e68d5..65db2a56b7 100644 --- a/src/test/compile-fail/dropck_vec_cycle_checked.rs +++ b/src/test/ui/span/dropck_vec_cycle_checked.rs @@ -107,13 +107,19 @@ fn f() { c3.v.push(CheckId(Cell::new(None))); c3.v.push(CheckId(Cell::new(None))); - c1.v[0].v.set(Some(&c2)); //~ ERROR `c2` does not live long enough - c1.v[1].v.set(Some(&c3)); //~ ERROR `c3` does not live long enough - c2.v[0].v.set(Some(&c2)); //~ ERROR `c2` does not live long enough - c2.v[1].v.set(Some(&c3)); //~ ERROR `c3` does not live long enough - c3.v[0].v.set(Some(&c1)); //~ ERROR `c1` does not live long enough - c3.v[1].v.set(Some(&c2)); //~ ERROR `c2` does not live long enough + c1.v[0].v.set(Some(&c2)); + c1.v[1].v.set(Some(&c3)); + c2.v[0].v.set(Some(&c2)); + c2.v[1].v.set(Some(&c3)); + c3.v[0].v.set(Some(&c1)); + c3.v[1].v.set(Some(&c2)); } +//~^ ERROR `c2` does not live long enough +//~| ERROR `c3` does not live long enough +//~| ERROR `c2` does not live long enough +//~| ERROR `c3` does not live long enough +//~| ERROR `c1` does not live long enough +//~| ERROR `c2` does not live long enough fn main() { f(); diff --git a/src/test/ui/span/dropck_vec_cycle_checked.stderr b/src/test/ui/span/dropck_vec_cycle_checked.stderr new file mode 100644 index 0000000000..961ac81cf8 --- /dev/null +++ b/src/test/ui/span/dropck_vec_cycle_checked.stderr @@ -0,0 +1,67 @@ +error: `c2` does not live long enough + --> $DIR/dropck_vec_cycle_checked.rs:116:1 + | +110 | c1.v[0].v.set(Some(&c2)); + | -- borrow occurs here +... +116 | } + | ^ `c2` dropped here while still borrowed + | + = note: values in a scope are dropped in the opposite order they are created + +error: `c3` does not live long enough + --> $DIR/dropck_vec_cycle_checked.rs:116:1 + | +111 | c1.v[1].v.set(Some(&c3)); + | -- borrow occurs here +... +116 | } + | ^ `c3` dropped here while still borrowed + | + = note: values in a scope are dropped in the opposite order they are created + +error: `c2` does not live long enough + --> $DIR/dropck_vec_cycle_checked.rs:116:1 + | +112 | c2.v[0].v.set(Some(&c2)); + | -- borrow occurs here +... +116 | } + | ^ `c2` dropped here while still borrowed + | + = note: values in a scope are dropped in the opposite order they are created + +error: `c3` does not live long enough + --> $DIR/dropck_vec_cycle_checked.rs:116:1 + | +113 | c2.v[1].v.set(Some(&c3)); + | -- borrow occurs here +... +116 | } + | ^ `c3` dropped here while still borrowed + | + = note: values in a scope are dropped in the opposite order they are created + +error: `c1` does not live long enough + --> $DIR/dropck_vec_cycle_checked.rs:116:1 + | +114 | c3.v[0].v.set(Some(&c1)); + | -- borrow occurs here +115 | c3.v[1].v.set(Some(&c2)); +116 | } + | ^ `c1` dropped here while still borrowed + | + = note: values in a scope are dropped in the opposite order they are created + +error: `c2` does not live long enough + --> $DIR/dropck_vec_cycle_checked.rs:116:1 + | +115 | c3.v[1].v.set(Some(&c2)); + | -- borrow occurs here +116 | } + | ^ `c2` dropped here while still borrowed + | + = note: values in a scope are dropped in the opposite order they are created + +error: aborting due to 6 previous errors + diff --git a/src/test/ui/span/issue-11925.stderr b/src/test/ui/span/issue-11925.stderr index 3fedb2884b..6ad9c27b8b 100644 --- a/src/test/ui/span/issue-11925.stderr +++ b/src/test/ui/span/issue-11925.stderr @@ -4,8 +4,8 @@ error: `x` does not live long enough 18 | let f = to_fn_once(move|| &x); | ^ | | - | does not live long enough - | borrowed value only lives until here + | borrow occurs here + | `x` dropped here while still borrowed ... 23 | } | - borrowed value needs to live until here diff --git a/src/test/compile-fail/issue-23338-locals-die-before-temps-of-body.rs b/src/test/ui/span/issue-23338-locals-die-before-temps-of-body.rs similarity index 94% rename from src/test/compile-fail/issue-23338-locals-die-before-temps-of-body.rs rename to src/test/ui/span/issue-23338-locals-die-before-temps-of-body.rs index 993893438e..a04edd99b8 100644 --- a/src/test/compile-fail/issue-23338-locals-die-before-temps-of-body.rs +++ b/src/test/ui/span/issue-23338-locals-die-before-temps-of-body.rs @@ -17,8 +17,9 @@ use std::cell::RefCell; fn foo(x: RefCell) -> String { let y = x; - y.borrow().clone() //~ ERROR `y` does not live long enough + y.borrow().clone() } +//~^ ERROR `y` does not live long enough fn foo2(x: RefCell) -> String { let ret = { diff --git a/src/test/ui/span/issue-23338-locals-die-before-temps-of-body.stderr b/src/test/ui/span/issue-23338-locals-die-before-temps-of-body.stderr new file mode 100644 index 0000000000..85a0002f24 --- /dev/null +++ b/src/test/ui/span/issue-23338-locals-die-before-temps-of-body.stderr @@ -0,0 +1,22 @@ +error: `y` does not live long enough + --> $DIR/issue-23338-locals-die-before-temps-of-body.rs:21:1 + | +20 | y.borrow().clone() + | - borrow occurs here +21 | } + | ^ `y` dropped here while still borrowed + | + = note: values in a scope are dropped in the opposite order they are created + +error: `y` does not live long enough + --> $DIR/issue-23338-locals-die-before-temps-of-body.rs:28:5 + | +27 | y.borrow().clone() //~ ERROR `y` does not live long enough + | - borrow occurs here +28 | }; + | ^- borrowed value needs to live until here + | | + | `y` dropped here while still borrowed + +error: aborting due to 2 previous errors + diff --git a/src/test/ui/span/issue-24690.rs b/src/test/ui/span/issue-24690.rs new file mode 100644 index 0000000000..def0d9aced --- /dev/null +++ b/src/test/ui/span/issue-24690.rs @@ -0,0 +1,22 @@ +// Copyright 2016 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +//! A test to ensure that helpful `note` messages aren't emitted more often +//! than necessary. + +// Although there are three errors, we should only get two "lint level defined +// here" notes pointing at the `warnings` span, one for each error type. +#![deny(warnings)] + +fn main() { + let theTwo = 2; + let theOtherTwo = 2; + println!("{}", theTwo); +} diff --git a/src/test/ui/span/issue-24690.stderr b/src/test/ui/span/issue-24690.stderr new file mode 100644 index 0000000000..0d2a2ef751 --- /dev/null +++ b/src/test/ui/span/issue-24690.stderr @@ -0,0 +1,32 @@ +error: unused variable: `theOtherTwo` + --> $DIR/issue-24690.rs:20:9 + | +20 | let theOtherTwo = 2; + | ^^^^^^^^^^^ + | +note: lint level defined here + --> $DIR/issue-24690.rs:16:9 + | +16 | #![deny(warnings)] + | ^^^^^^^^ + +error: variable `theTwo` should have a snake case name such as `the_two` + --> $DIR/issue-24690.rs:19:9 + | +19 | let theTwo = 2; + | ^^^^^^ + | +note: lint level defined here + --> $DIR/issue-24690.rs:16:9 + | +16 | #![deny(warnings)] + | ^^^^^^^^ + +error: variable `theOtherTwo` should have a snake case name such as `the_other_two` + --> $DIR/issue-24690.rs:20:9 + | +20 | let theOtherTwo = 2; + | ^^^^^^^^^^^ + +error: aborting due to 3 previous errors + diff --git a/src/test/compile-fail/issue-24805-dropck-child-has-items-via-parent.rs b/src/test/ui/span/issue-24805-dropck-child-has-items-via-parent.rs similarity index 95% rename from src/test/compile-fail/issue-24805-dropck-child-has-items-via-parent.rs rename to src/test/ui/span/issue-24805-dropck-child-has-items-via-parent.rs index 37ef81e686..acd363fc6b 100644 --- a/src/test/compile-fail/issue-24805-dropck-child-has-items-via-parent.rs +++ b/src/test/ui/span/issue-24805-dropck-child-has-items-via-parent.rs @@ -35,11 +35,12 @@ fn f_child() { d1 = D_Child(1); // ... we store a reference to `d1` within `_d` ... - _d = D_Child(&d1); //~ ERROR `d1` does not live long enough + _d = D_Child(&d1); // ... dropck *should* complain, because Drop of _d could (and // does) access the already dropped `d1` via the `foo` method. } +//~^ ERROR `d1` does not live long enough fn main() { f_child(); diff --git a/src/test/ui/span/issue-24805-dropck-child-has-items-via-parent.stderr b/src/test/ui/span/issue-24805-dropck-child-has-items-via-parent.stderr new file mode 100644 index 0000000000..a622e7cfb7 --- /dev/null +++ b/src/test/ui/span/issue-24805-dropck-child-has-items-via-parent.stderr @@ -0,0 +1,13 @@ +error: `d1` does not live long enough + --> $DIR/issue-24805-dropck-child-has-items-via-parent.rs:42:1 + | +38 | _d = D_Child(&d1); + | -- borrow occurs here +... +42 | } + | ^ `d1` dropped here while still borrowed + | + = note: values in a scope are dropped in the opposite order they are created + +error: aborting due to previous error + diff --git a/src/test/compile-fail/issue-24805-dropck-trait-has-items.rs b/src/test/ui/span/issue-24805-dropck-trait-has-items.rs similarity index 88% rename from src/test/compile-fail/issue-24805-dropck-trait-has-items.rs rename to src/test/ui/span/issue-24805-dropck-trait-has-items.rs index 0da1b9fc6e..3deb71411e 100644 --- a/src/test/compile-fail/issue-24805-dropck-trait-has-items.rs +++ b/src/test/ui/span/issue-24805-dropck-trait-has-items.rs @@ -44,18 +44,21 @@ impl_drop!{HasType, D_HasType} fn f_sm() { let (_d, d1); d1 = D_HasSelfMethod(1); - _d = D_HasSelfMethod(&d1); //~ ERROR `d1` does not live long enough + _d = D_HasSelfMethod(&d1); } +//~^ ERROR `d1` does not live long enough fn f_mwsa() { let (_d, d1); d1 = D_HasMethodWithSelfArg(1); - _d = D_HasMethodWithSelfArg(&d1); //~ ERROR `d1` does not live long enough + _d = D_HasMethodWithSelfArg(&d1); } +//~^ ERROR `d1` does not live long enough fn f_t() { let (_d, d1); d1 = D_HasType(1); - _d = D_HasType(&d1); //~ ERROR `d1` does not live long enough + _d = D_HasType(&d1); } +//~^ ERROR `d1` does not live long enough fn main() { f_sm(); diff --git a/src/test/ui/span/issue-24805-dropck-trait-has-items.stderr b/src/test/ui/span/issue-24805-dropck-trait-has-items.stderr new file mode 100644 index 0000000000..d06c8af62e --- /dev/null +++ b/src/test/ui/span/issue-24805-dropck-trait-has-items.stderr @@ -0,0 +1,32 @@ +error: `d1` does not live long enough + --> $DIR/issue-24805-dropck-trait-has-items.rs:48:1 + | +47 | _d = D_HasSelfMethod(&d1); + | -- borrow occurs here +48 | } + | ^ `d1` dropped here while still borrowed + | + = note: values in a scope are dropped in the opposite order they are created + +error: `d1` does not live long enough + --> $DIR/issue-24805-dropck-trait-has-items.rs:54:1 + | +53 | _d = D_HasMethodWithSelfArg(&d1); + | -- borrow occurs here +54 | } + | ^ `d1` dropped here while still borrowed + | + = note: values in a scope are dropped in the opposite order they are created + +error: `d1` does not live long enough + --> $DIR/issue-24805-dropck-trait-has-items.rs:60:1 + | +59 | _d = D_HasType(&d1); + | -- borrow occurs here +60 | } + | ^ `d1` dropped here while still borrowed + | + = note: values in a scope are dropped in the opposite order they are created + +error: aborting due to 3 previous errors + diff --git a/src/test/compile-fail/issue-24895-copy-clone-dropck.rs b/src/test/ui/span/issue-24895-copy-clone-dropck.rs similarity index 93% rename from src/test/compile-fail/issue-24895-copy-clone-dropck.rs rename to src/test/ui/span/issue-24895-copy-clone-dropck.rs index 2883511736..a4207eb0aa 100644 --- a/src/test/compile-fail/issue-24895-copy-clone-dropck.rs +++ b/src/test/ui/span/issue-24895-copy-clone-dropck.rs @@ -34,5 +34,5 @@ impl Drop for D { fn main() { let (d2, d1); d1 = D(34, "d1"); - d2 = D(S(&d1, "inner"), "d2"); //~ ERROR `d1` does not live long enough -} + d2 = D(S(&d1, "inner"), "d2"); +} //~ ERROR `d1` does not live long enough diff --git a/src/test/ui/span/issue-24895-copy-clone-dropck.stderr b/src/test/ui/span/issue-24895-copy-clone-dropck.stderr new file mode 100644 index 0000000000..160bfb6390 --- /dev/null +++ b/src/test/ui/span/issue-24895-copy-clone-dropck.stderr @@ -0,0 +1,12 @@ +error: `d1` does not live long enough + --> $DIR/issue-24895-copy-clone-dropck.rs:38:1 + | +37 | d2 = D(S(&d1, "inner"), "d2"); + | -- borrow occurs here +38 | } //~ ERROR `d1` does not live long enough + | ^ `d1` dropped here while still borrowed + | + = note: values in a scope are dropped in the opposite order they are created + +error: aborting due to previous error + diff --git a/src/test/compile-fail/issue-25199.rs b/src/test/ui/span/issue-25199.rs similarity index 93% rename from src/test/compile-fail/issue-25199.rs rename to src/test/ui/span/issue-25199.rs index 74ea1ca294..b88c58c29a 100644 --- a/src/test/compile-fail/issue-25199.rs +++ b/src/test/ui/span/issue-25199.rs @@ -77,7 +77,9 @@ impl<'a> Drop for Test<'a> { fn main() { let container = Container::new(); - let test = Test{test: &container}; //~ ERROR `container` does not live long enough + let test = Test{test: &container}; println!("container.v[30]: {:?}", container.v.v[30]); - container.store(test); //~ ERROR `container` does not live long enough + container.store(test); } +//~^ ERROR `container` does not live long enough +//~| ERROR `container` does not live long enough diff --git a/src/test/ui/span/issue-25199.stderr b/src/test/ui/span/issue-25199.stderr new file mode 100644 index 0000000000..3c8ee07a1f --- /dev/null +++ b/src/test/ui/span/issue-25199.stderr @@ -0,0 +1,23 @@ +error: `container` does not live long enough + --> $DIR/issue-25199.rs:83:1 + | +80 | let test = Test{test: &container}; + | --------- borrow occurs here +... +83 | } + | ^ `container` dropped here while still borrowed + | + = note: values in a scope are dropped in the opposite order they are created + +error: `container` does not live long enough + --> $DIR/issue-25199.rs:83:1 + | +82 | container.store(test); + | --------- borrow occurs here +83 | } + | ^ `container` dropped here while still borrowed + | + = note: values in a scope are dropped in the opposite order they are created + +error: aborting due to 2 previous errors + diff --git a/src/test/compile-fail/issue-26656.rs b/src/test/ui/span/issue-26656.rs similarity index 96% rename from src/test/compile-fail/issue-26656.rs rename to src/test/ui/span/issue-26656.rs index e5fa65498d..621da477dd 100644 --- a/src/test/compile-fail/issue-26656.rs +++ b/src/test/ui/span/issue-26656.rs @@ -48,5 +48,5 @@ fn main() { trigger: Box::new(()) }; ticking = Bomb { usable: true }; zook.button = B::BigRedButton(&ticking); - //~^ ERROR `ticking` does not live long enough } +//~^ ERROR `ticking` does not live long enough diff --git a/src/test/ui/span/issue-26656.stderr b/src/test/ui/span/issue-26656.stderr new file mode 100644 index 0000000000..f960844c81 --- /dev/null +++ b/src/test/ui/span/issue-26656.stderr @@ -0,0 +1,12 @@ +error: `ticking` does not live long enough + --> $DIR/issue-26656.rs:51:1 + | +50 | zook.button = B::BigRedButton(&ticking); + | ------- borrow occurs here +51 | } + | ^ `ticking` dropped here while still borrowed + | + = note: values in a scope are dropped in the opposite order they are created + +error: aborting due to previous error + diff --git a/src/test/compile-fail/issue-29106.rs b/src/test/ui/span/issue-29106.rs similarity index 83% rename from src/test/compile-fail/issue-29106.rs rename to src/test/ui/span/issue-29106.rs index 1872c62e36..8d28c64f26 100644 --- a/src/test/compile-fail/issue-29106.rs +++ b/src/test/ui/span/issue-29106.rs @@ -23,12 +23,12 @@ fn main() { { let (y, x); x = "alive".to_string(); - y = Arc::new(Foo(&x)); //~ ERROR `x` does not live long enough - } + y = Arc::new(Foo(&x)); + } //~ ERROR `x` does not live long enough { let (y, x); x = "alive".to_string(); - y = Rc::new(Foo(&x)); //~ ERROR `x` does not live long enough - } + y = Rc::new(Foo(&x)); + } //~ ERROR `x` does not live long enough } diff --git a/src/test/ui/span/issue-29106.stderr b/src/test/ui/span/issue-29106.stderr new file mode 100644 index 0000000000..a7d3b84dab --- /dev/null +++ b/src/test/ui/span/issue-29106.stderr @@ -0,0 +1,22 @@ +error: `x` does not live long enough + --> $DIR/issue-29106.rs:27:5 + | +26 | y = Arc::new(Foo(&x)); + | - borrow occurs here +27 | } //~ ERROR `x` does not live long enough + | ^ `x` dropped here while still borrowed + | + = note: values in a scope are dropped in the opposite order they are created + +error: `x` does not live long enough + --> $DIR/issue-29106.rs:33:5 + | +32 | y = Rc::new(Foo(&x)); + | - borrow occurs here +33 | } //~ ERROR `x` does not live long enough + | ^ `x` dropped here while still borrowed + | + = note: values in a scope are dropped in the opposite order they are created + +error: aborting due to 2 previous errors + diff --git a/src/test/ui/span/issue-36537.rs b/src/test/ui/span/issue-36537.rs new file mode 100644 index 0000000000..33182e02fa --- /dev/null +++ b/src/test/ui/span/issue-36537.rs @@ -0,0 +1,18 @@ +// 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. + +fn main() { + let p; + let a = 42; + p = &a; //~ NOTE borrow occurs here +} +//~^ ERROR `a` does not live long enough +//~| NOTE `a` dropped here while still borrowed +//~| NOTE values in a scope are dropped in the opposite order they are created diff --git a/src/test/ui/span/issue-36537.stderr b/src/test/ui/span/issue-36537.stderr new file mode 100644 index 0000000000..a335194580 --- /dev/null +++ b/src/test/ui/span/issue-36537.stderr @@ -0,0 +1,12 @@ +error: `a` does not live long enough + --> $DIR/issue-36537.rs:15:1 + | +14 | p = &a; //~ NOTE borrow occurs here + | - borrow occurs here +15 | } + | ^ `a` dropped here while still borrowed + | + = note: values in a scope are dropped in the opposite order they are created + +error: aborting due to previous error + diff --git a/src/test/compile-fail/issue28498-reject-ex1.rs b/src/test/ui/span/issue28498-reject-ex1.rs similarity index 93% rename from src/test/compile-fail/issue28498-reject-ex1.rs rename to src/test/ui/span/issue28498-reject-ex1.rs index cee7c57c20..bed768005b 100644 --- a/src/test/compile-fail/issue28498-reject-ex1.rs +++ b/src/test/ui/span/issue28498-reject-ex1.rs @@ -42,7 +42,7 @@ fn main() { foo.data.push(Concrete(0, Cell::new(None))); foo.data[0].1.set(Some(&foo.data[1])); - //~^ ERROR `foo.data` does not live long enough foo.data[1].1.set(Some(&foo.data[0])); - //~^ ERROR `foo.data` does not live long enough } +//~^ ERROR `foo.data` does not live long enough +//~| ERROR `foo.data` does not live long enough diff --git a/src/test/ui/span/issue28498-reject-ex1.stderr b/src/test/ui/span/issue28498-reject-ex1.stderr new file mode 100644 index 0000000000..b5fbe99ec7 --- /dev/null +++ b/src/test/ui/span/issue28498-reject-ex1.stderr @@ -0,0 +1,23 @@ +error: `foo.data` does not live long enough + --> $DIR/issue28498-reject-ex1.rs:46:1 + | +44 | foo.data[0].1.set(Some(&foo.data[1])); + | -------- borrow occurs here +45 | foo.data[1].1.set(Some(&foo.data[0])); +46 | } + | ^ `foo.data` dropped here while still borrowed + | + = note: values in a scope are dropped in the opposite order they are created + +error: `foo.data` does not live long enough + --> $DIR/issue28498-reject-ex1.rs:46:1 + | +45 | foo.data[1].1.set(Some(&foo.data[0])); + | -------- borrow occurs here +46 | } + | ^ `foo.data` dropped here while still borrowed + | + = note: values in a scope are dropped in the opposite order they are created + +error: aborting due to 2 previous errors + diff --git a/src/test/compile-fail/issue28498-reject-lifetime-param.rs b/src/test/ui/span/issue28498-reject-lifetime-param.rs similarity index 92% rename from src/test/compile-fail/issue28498-reject-lifetime-param.rs rename to src/test/ui/span/issue28498-reject-lifetime-param.rs index 92028c7a81..7e7893ac3c 100644 --- a/src/test/compile-fail/issue28498-reject-lifetime-param.rs +++ b/src/test/ui/span/issue28498-reject-lifetime-param.rs @@ -40,9 +40,9 @@ fn main() { last_dropped = ScribbleOnDrop(format!("last")); first_dropped = ScribbleOnDrop(format!("first")); foo0 = Foo(0, &last_dropped); - //~^ ERROR `last_dropped` does not live long enough foo1 = Foo(1, &first_dropped); - //~^ ERROR `first_dropped` does not live long enough println!("foo0.1: {:?} foo1.1: {:?}", foo0.1, foo1.1); } +//~^ ERROR `last_dropped` does not live long enough +//~| ERROR `first_dropped` does not live long enough diff --git a/src/test/ui/span/issue28498-reject-lifetime-param.stderr b/src/test/ui/span/issue28498-reject-lifetime-param.stderr new file mode 100644 index 0000000000..debb835456 --- /dev/null +++ b/src/test/ui/span/issue28498-reject-lifetime-param.stderr @@ -0,0 +1,24 @@ +error: `last_dropped` does not live long enough + --> $DIR/issue28498-reject-lifetime-param.rs:46:1 + | +42 | foo0 = Foo(0, &last_dropped); + | ------------ borrow occurs here +... +46 | } + | ^ `last_dropped` dropped here while still borrowed + | + = note: values in a scope are dropped in the opposite order they are created + +error: `first_dropped` does not live long enough + --> $DIR/issue28498-reject-lifetime-param.rs:46:1 + | +43 | foo1 = Foo(1, &first_dropped); + | ------------- borrow occurs here +... +46 | } + | ^ `first_dropped` dropped here while still borrowed + | + = note: values in a scope are dropped in the opposite order they are created + +error: aborting due to 2 previous errors + diff --git a/src/test/compile-fail/issue28498-reject-passed-to-fn.rs b/src/test/ui/span/issue28498-reject-passed-to-fn.rs similarity index 93% rename from src/test/compile-fail/issue28498-reject-passed-to-fn.rs rename to src/test/ui/span/issue28498-reject-passed-to-fn.rs index 27378b1e0b..54fc20b62f 100644 --- a/src/test/compile-fail/issue28498-reject-passed-to-fn.rs +++ b/src/test/ui/span/issue28498-reject-passed-to-fn.rs @@ -42,9 +42,9 @@ fn main() { last_dropped = ScribbleOnDrop(format!("last")); first_dropped = ScribbleOnDrop(format!("first")); foo0 = Foo(0, &last_dropped, Box::new(callback)); - //~^ ERROR `last_dropped` does not live long enough foo1 = Foo(1, &first_dropped, Box::new(callback)); - //~^ ERROR `first_dropped` does not live long enough println!("foo0.1: {:?} foo1.1: {:?}", foo0.1, foo1.1); } +//~^ ERROR `last_dropped` does not live long enough +//~| ERROR `first_dropped` does not live long enough diff --git a/src/test/ui/span/issue28498-reject-passed-to-fn.stderr b/src/test/ui/span/issue28498-reject-passed-to-fn.stderr new file mode 100644 index 0000000000..7d3ac3e9d0 --- /dev/null +++ b/src/test/ui/span/issue28498-reject-passed-to-fn.stderr @@ -0,0 +1,24 @@ +error: `last_dropped` does not live long enough + --> $DIR/issue28498-reject-passed-to-fn.rs:48:1 + | +44 | foo0 = Foo(0, &last_dropped, Box::new(callback)); + | ------------ borrow occurs here +... +48 | } + | ^ `last_dropped` dropped here while still borrowed + | + = note: values in a scope are dropped in the opposite order they are created + +error: `first_dropped` does not live long enough + --> $DIR/issue28498-reject-passed-to-fn.rs:48:1 + | +45 | foo1 = Foo(1, &first_dropped, Box::new(callback)); + | ------------- borrow occurs here +... +48 | } + | ^ `first_dropped` dropped here while still borrowed + | + = note: values in a scope are dropped in the opposite order they are created + +error: aborting due to 2 previous errors + diff --git a/src/test/compile-fail/issue28498-reject-trait-bound.rs b/src/test/ui/span/issue28498-reject-trait-bound.rs similarity index 92% rename from src/test/compile-fail/issue28498-reject-trait-bound.rs rename to src/test/ui/span/issue28498-reject-trait-bound.rs index 3904d68ba1..6164beaf85 100644 --- a/src/test/compile-fail/issue28498-reject-trait-bound.rs +++ b/src/test/ui/span/issue28498-reject-trait-bound.rs @@ -42,9 +42,9 @@ fn main() { last_dropped = ScribbleOnDrop(format!("last")); first_dropped = ScribbleOnDrop(format!("first")); foo0 = Foo(0, &last_dropped); - //~^ ERROR `last_dropped` does not live long enough foo1 = Foo(1, &first_dropped); - //~^ ERROR `first_dropped` does not live long enough println!("foo0.1: {:?} foo1.1: {:?}", foo0.1, foo1.1); } +//~^ ERROR `last_dropped` does not live long enough +//~| ERROR `first_dropped` does not live long enough diff --git a/src/test/ui/span/issue28498-reject-trait-bound.stderr b/src/test/ui/span/issue28498-reject-trait-bound.stderr new file mode 100644 index 0000000000..ae96cace91 --- /dev/null +++ b/src/test/ui/span/issue28498-reject-trait-bound.stderr @@ -0,0 +1,24 @@ +error: `last_dropped` does not live long enough + --> $DIR/issue28498-reject-trait-bound.rs:48:1 + | +44 | foo0 = Foo(0, &last_dropped); + | ------------ borrow occurs here +... +48 | } + | ^ `last_dropped` dropped here while still borrowed + | + = note: values in a scope are dropped in the opposite order they are created + +error: `first_dropped` does not live long enough + --> $DIR/issue28498-reject-trait-bound.rs:48:1 + | +45 | foo1 = Foo(1, &first_dropped); + | ------------- borrow occurs here +... +48 | } + | ^ `first_dropped` dropped here while still borrowed + | + = note: values in a scope are dropped in the opposite order they are created + +error: aborting due to 2 previous errors + diff --git a/src/test/compile-fail/impl-trait/loan-extend.rs b/src/test/ui/span/loan-extend.rs similarity index 76% rename from src/test/compile-fail/impl-trait/loan-extend.rs rename to src/test/ui/span/loan-extend.rs index 8dfcb08cff..a4b951daab 100644 --- a/src/test/compile-fail/impl-trait/loan-extend.rs +++ b/src/test/ui/span/loan-extend.rs @@ -17,7 +17,8 @@ fn main() { let long; let mut short = 0; long = borrow(&mut short); - //~^ ERROR `short` does not live long enough - //~| NOTE does not live long enough - //~| NOTE values in a scope are dropped in the opposite order they are created -} //~ borrowed value dropped before borrower + //~^ NOTE borrow occurs here +} +//~^ ERROR `short` does not live long enough +//~| NOTE `short` dropped here while still borrowed +//~| NOTE values in a scope are dropped in the opposite order they are created diff --git a/src/test/ui/span/loan-extend.stderr b/src/test/ui/span/loan-extend.stderr new file mode 100644 index 0000000000..b0f191e29d --- /dev/null +++ b/src/test/ui/span/loan-extend.stderr @@ -0,0 +1,13 @@ +error: `short` does not live long enough + --> $DIR/loan-extend.rs:21:1 + | +19 | long = borrow(&mut short); + | ----- borrow occurs here +20 | //~^ NOTE borrow occurs here +21 | } + | ^ `short` dropped here while still borrowed + | + = note: values in a scope are dropped in the opposite order they are created + +error: aborting due to previous error + diff --git a/src/test/compile-fail/mut-ptr-cant-outlive-ref.rs b/src/test/ui/span/mut-ptr-cant-outlive-ref.rs similarity index 100% rename from src/test/compile-fail/mut-ptr-cant-outlive-ref.rs rename to src/test/ui/span/mut-ptr-cant-outlive-ref.rs diff --git a/src/test/ui/span/mut-ptr-cant-outlive-ref.stderr b/src/test/ui/span/mut-ptr-cant-outlive-ref.stderr new file mode 100644 index 0000000000..0417eb075a --- /dev/null +++ b/src/test/ui/span/mut-ptr-cant-outlive-ref.stderr @@ -0,0 +1,12 @@ +error: `b` does not live long enough + --> $DIR/mut-ptr-cant-outlive-ref.rs:19:5 + | +18 | p = &*b; //~ ERROR `b` does not live long enough + | - borrow occurs here +19 | } + | ^ `b` dropped here while still borrowed +20 | } + | - borrowed value needs to live until here + +error: aborting due to previous error + diff --git a/src/test/compile-fail/range-2.rs b/src/test/ui/span/range-2.rs similarity index 100% rename from src/test/compile-fail/range-2.rs rename to src/test/ui/span/range-2.rs diff --git a/src/test/ui/span/range-2.stderr b/src/test/ui/span/range-2.stderr new file mode 100644 index 0000000000..9f11de77be --- /dev/null +++ b/src/test/ui/span/range-2.stderr @@ -0,0 +1,24 @@ +error: `a` does not live long enough + --> $DIR/range-2.rs:20:5 + | +17 | &a..&b + | - borrow occurs here +... +20 | }; + | ^ `a` dropped here while still borrowed +21 | } + | - borrowed value needs to live until here + +error: `b` does not live long enough + --> $DIR/range-2.rs:20:5 + | +17 | &a..&b + | - borrow occurs here +... +20 | }; + | ^ `b` dropped here while still borrowed +21 | } + | - borrowed value needs to live until here + +error: aborting due to 2 previous errors + diff --git a/src/test/compile-fail/regionck-unboxed-closure-lifetimes.rs b/src/test/ui/span/regionck-unboxed-closure-lifetimes.rs similarity index 100% rename from src/test/compile-fail/regionck-unboxed-closure-lifetimes.rs rename to src/test/ui/span/regionck-unboxed-closure-lifetimes.rs diff --git a/src/test/ui/span/regionck-unboxed-closure-lifetimes.stderr b/src/test/ui/span/regionck-unboxed-closure-lifetimes.stderr new file mode 100644 index 0000000000..9c369e03e3 --- /dev/null +++ b/src/test/ui/span/regionck-unboxed-closure-lifetimes.stderr @@ -0,0 +1,13 @@ +error: `c` does not live long enough + --> $DIR/regionck-unboxed-closure-lifetimes.rs:19:5 + | +17 | let c_ref = &c; //~ ERROR `c` does not live long enough + | - borrow occurs here +18 | f = move |a: isize, b: isize| { a + b + *c_ref }; +19 | } + | ^ `c` dropped here while still borrowed +20 | } + | - borrowed value needs to live until here + +error: aborting due to previous error + diff --git a/src/test/compile-fail/regions-close-over-type-parameter-2.rs b/src/test/ui/span/regions-close-over-type-parameter-2.rs similarity index 100% rename from src/test/compile-fail/regions-close-over-type-parameter-2.rs rename to src/test/ui/span/regions-close-over-type-parameter-2.rs diff --git a/src/test/ui/span/regions-close-over-type-parameter-2.stderr b/src/test/ui/span/regions-close-over-type-parameter-2.stderr new file mode 100644 index 0000000000..ea652da7da --- /dev/null +++ b/src/test/ui/span/regions-close-over-type-parameter-2.stderr @@ -0,0 +1,13 @@ +error: `tmp0` does not live long enough + --> $DIR/regions-close-over-type-parameter-2.rs:35:5 + | +33 | let tmp1 = &tmp0; //~ ERROR `tmp0` does not live long enough + | ---- borrow occurs here +34 | repeater3(tmp1) +35 | }; + | ^- borrowed value needs to live until here + | | + | `tmp0` dropped here while still borrowed + +error: aborting due to previous error + diff --git a/src/test/compile-fail/regions-escape-loop-via-variable.rs b/src/test/ui/span/regions-escape-loop-via-variable.rs similarity index 100% rename from src/test/compile-fail/regions-escape-loop-via-variable.rs rename to src/test/ui/span/regions-escape-loop-via-variable.rs diff --git a/src/test/ui/span/regions-escape-loop-via-variable.stderr b/src/test/ui/span/regions-escape-loop-via-variable.stderr new file mode 100644 index 0000000000..09f2154905 --- /dev/null +++ b/src/test/ui/span/regions-escape-loop-via-variable.stderr @@ -0,0 +1,12 @@ +error: `x` does not live long enough + --> $DIR/regions-escape-loop-via-variable.rs:22:5 + | +21 | p = &x; //~ ERROR `x` does not live long enough + | - borrow occurs here +22 | } + | ^ `x` dropped here while still borrowed +23 | } + | - borrowed value needs to live until here + +error: aborting due to previous error + diff --git a/src/test/compile-fail/regions-escape-loop-via-vec.rs b/src/test/ui/span/regions-escape-loop-via-vec.rs similarity index 97% rename from src/test/compile-fail/regions-escape-loop-via-vec.rs rename to src/test/ui/span/regions-escape-loop-via-vec.rs index f5ea7a2108..8982b5cd98 100644 --- a/src/test/compile-fail/regions-escape-loop-via-vec.rs +++ b/src/test/ui/span/regions-escape-loop-via-vec.rs @@ -11,7 +11,7 @@ // The type of `y` ends up getting inferred to the type of the block. fn broken() { let mut x = 3; - let mut _y = vec!(&mut x); + let mut _y = vec![&mut x]; //~^ NOTE borrow of `x` occurs here //~| NOTE borrow of `x` occurs here //~| NOTE borrow of `x` occurs here diff --git a/src/test/ui/span/regions-escape-loop-via-vec.stderr b/src/test/ui/span/regions-escape-loop-via-vec.stderr new file mode 100644 index 0000000000..58f7849e44 --- /dev/null +++ b/src/test/ui/span/regions-escape-loop-via-vec.stderr @@ -0,0 +1,41 @@ +error: `z` does not live long enough + --> $DIR/regions-escape-loop-via-vec.rs:26:5 + | +22 | _y.push(&mut z); //~ ERROR `z` does not live long enough + | - borrow occurs here +... +26 | } + | ^ `z` dropped here while still borrowed +27 | //~^ NOTE borrowed value only lives until here +28 | } + | - borrowed value needs to live until here + +error[E0503]: cannot use `x` because it was mutably borrowed + --> $DIR/regions-escape-loop-via-vec.rs:18:11 + | +14 | let mut _y = vec![&mut x]; + | - borrow of `x` occurs here +... +18 | while x < 10 { //~ ERROR cannot use `x` because it was mutably borrowed + | ^ use of borrowed `x` + +error[E0503]: cannot use `x` because it was mutably borrowed + --> $DIR/regions-escape-loop-via-vec.rs:20:13 + | +14 | let mut _y = vec![&mut x]; + | - borrow of `x` occurs here +... +20 | let mut z = x; //~ ERROR cannot use `x` because it was mutably borrowed + | ^^^^^ use of borrowed `x` + +error[E0506]: cannot assign to `x` because it is borrowed + --> $DIR/regions-escape-loop-via-vec.rs:24:9 + | +14 | let mut _y = vec![&mut x]; + | - borrow of `x` occurs here +... +24 | x += 1; //~ ERROR cannot assign + | ^^^^^^ assignment to borrowed `x` occurs here + +error: aborting due to 4 previous errors + diff --git a/src/test/compile-fail/regions-infer-borrow-scope-within-loop.rs b/src/test/ui/span/regions-infer-borrow-scope-within-loop.rs similarity index 100% rename from src/test/compile-fail/regions-infer-borrow-scope-within-loop.rs rename to src/test/ui/span/regions-infer-borrow-scope-within-loop.rs diff --git a/src/test/ui/span/regions-infer-borrow-scope-within-loop.stderr b/src/test/ui/span/regions-infer-borrow-scope-within-loop.stderr new file mode 100644 index 0000000000..0e7b64ec2b --- /dev/null +++ b/src/test/ui/span/regions-infer-borrow-scope-within-loop.stderr @@ -0,0 +1,14 @@ +error: `*x` does not live long enough + --> $DIR/regions-infer-borrow-scope-within-loop.rs:28:5 + | +24 | y = borrow(&*x); //~ ERROR `*x` does not live long enough + | -- borrow occurs here +... +28 | } + | ^ `*x` dropped here while still borrowed +29 | assert!(*y != 0); +30 | } + | - borrowed value needs to live until here + +error: aborting due to previous error + diff --git a/src/test/compile-fail/send-is-not-static-ensures-scoping.rs b/src/test/ui/span/send-is-not-static-ensures-scoping.rs similarity index 100% rename from src/test/compile-fail/send-is-not-static-ensures-scoping.rs rename to src/test/ui/span/send-is-not-static-ensures-scoping.rs diff --git a/src/test/ui/span/send-is-not-static-ensures-scoping.stderr b/src/test/ui/span/send-is-not-static-ensures-scoping.stderr new file mode 100644 index 0000000000..5897921476 --- /dev/null +++ b/src/test/ui/span/send-is-not-static-ensures-scoping.stderr @@ -0,0 +1,28 @@ +error: `x` does not live long enough + --> $DIR/send-is-not-static-ensures-scoping.rs:32:5 + | +26 | let y = &x; //~ ERROR `x` does not live long enough + | - borrow occurs here +... +32 | }; + | ^ `x` dropped here while still borrowed +... +35 | } + | - borrowed value needs to live until here + +error: `y` does not live long enough + --> $DIR/send-is-not-static-ensures-scoping.rs:29:22 + | +28 | scoped(|| { + | -- capture occurs here +29 | let _z = y; + | ^ does not live long enough +... +32 | }; + | - borrowed value only lives until here +... +35 | } + | - borrowed value needs to live until here + +error: aborting due to 2 previous errors + diff --git a/src/test/compile-fail/send-is-not-static-std-sync-2.rs b/src/test/ui/span/send-is-not-static-std-sync-2.rs similarity index 100% rename from src/test/compile-fail/send-is-not-static-std-sync-2.rs rename to src/test/ui/span/send-is-not-static-std-sync-2.rs diff --git a/src/test/ui/span/send-is-not-static-std-sync-2.stderr b/src/test/ui/span/send-is-not-static-std-sync-2.stderr new file mode 100644 index 0000000000..08f85f17bf --- /dev/null +++ b/src/test/ui/span/send-is-not-static-std-sync-2.stderr @@ -0,0 +1,36 @@ +error: `x` does not live long enough + --> $DIR/send-is-not-static-std-sync-2.rs:22:5 + | +21 | Mutex::new(&x) //~ ERROR does not live long enough + | - borrow occurs here +22 | }; + | ^ `x` dropped here while still borrowed +... +25 | } + | - borrowed value needs to live until here + +error: `x` does not live long enough + --> $DIR/send-is-not-static-std-sync-2.rs:31:5 + | +30 | RwLock::new(&x) //~ ERROR does not live long enough + | - borrow occurs here +31 | }; + | ^ `x` dropped here while still borrowed +32 | let _dangling = *lock.read().unwrap(); +33 | } + | - borrowed value needs to live until here + +error: `x` does not live long enough + --> $DIR/send-is-not-static-std-sync-2.rs:41:5 + | +39 | let _ = tx.send(&x); //~ ERROR does not live long enough + | - borrow occurs here +40 | (tx, rx) +41 | }; + | ^ `x` dropped here while still borrowed +... +44 | } + | - borrowed value needs to live until here + +error: aborting due to 3 previous errors + diff --git a/src/test/compile-fail/send-is-not-static-std-sync.rs b/src/test/ui/span/send-is-not-static-std-sync.rs similarity index 100% rename from src/test/compile-fail/send-is-not-static-std-sync.rs rename to src/test/ui/span/send-is-not-static-std-sync.rs diff --git a/src/test/ui/span/send-is-not-static-std-sync.stderr b/src/test/ui/span/send-is-not-static-std-sync.stderr new file mode 100644 index 0000000000..a86cf1e588 --- /dev/null +++ b/src/test/ui/span/send-is-not-static-std-sync.stderr @@ -0,0 +1,56 @@ +error: `z` does not live long enough + --> $DIR/send-is-not-static-std-sync.rs:27:5 + | +26 | *lock.lock().unwrap() = &z; //~ ERROR does not live long enough + | - borrow occurs here +27 | } + | ^ `z` dropped here while still borrowed +28 | } + | - borrowed value needs to live until here + +error[E0505]: cannot move out of `y` because it is borrowed + --> $DIR/send-is-not-static-std-sync.rs:23:10 + | +22 | *lock.lock().unwrap() = &*y; + | -- borrow of `*y` occurs here +23 | drop(y); //~ ERROR cannot move out + | ^ move out of `y` occurs here + +error: `z` does not live long enough + --> $DIR/send-is-not-static-std-sync.rs:39:5 + | +38 | *lock.write().unwrap() = &z; //~ ERROR does not live long enough + | - borrow occurs here +39 | } + | ^ `z` dropped here while still borrowed +40 | } + | - borrowed value needs to live until here + +error[E0505]: cannot move out of `y` because it is borrowed + --> $DIR/send-is-not-static-std-sync.rs:35:10 + | +34 | *lock.write().unwrap() = &*y; + | -- borrow of `*y` occurs here +35 | drop(y); //~ ERROR cannot move out + | ^ move out of `y` occurs here + +error: `z` does not live long enough + --> $DIR/send-is-not-static-std-sync.rs:53:5 + | +52 | tx.send(&z).unwrap(); //~ ERROR does not live long enough + | - borrow occurs here +53 | } + | ^ `z` dropped here while still borrowed +54 | } + | - borrowed value needs to live until here + +error[E0505]: cannot move out of `y` because it is borrowed + --> $DIR/send-is-not-static-std-sync.rs:49:10 + | +48 | tx.send(&*y); + | -- borrow of `*y` occurs here +49 | drop(y); //~ ERROR cannot move out + | ^ move out of `y` occurs here + +error: aborting due to 6 previous errors + diff --git a/src/test/ui/span/type-binding.stderr b/src/test/ui/span/type-binding.stderr index 3cd1791a34..dc37acaf3f 100644 --- a/src/test/ui/span/type-binding.stderr +++ b/src/test/ui/span/type-binding.stderr @@ -2,7 +2,7 @@ error[E0220]: associated type `Trget` not found for `std::ops::Deref` --> $DIR/type-binding.rs:16:20 | 16 | fn homura>(_: T) {} - | ^^^^^^^^^^^ + | ^^^^^^^^^^^ associated type `Trget` not found error: aborting due to previous error diff --git a/src/test/compile-fail/vec-must-not-hide-type-from-dropck.rs b/src/test/ui/span/vec-must-not-hide-type-from-dropck.rs similarity index 96% rename from src/test/compile-fail/vec-must-not-hide-type-from-dropck.rs rename to src/test/ui/span/vec-must-not-hide-type-from-dropck.rs index c8f4326bb2..310ab20489 100644 --- a/src/test/compile-fail/vec-must-not-hide-type-from-dropck.rs +++ b/src/test/ui/span/vec-must-not-hide-type-from-dropck.rs @@ -124,9 +124,11 @@ fn f() { c1.v.push(CheckId(Cell::new(None))); c2.v.push(CheckId(Cell::new(None))); - c1.v[0].v.set(Some(&c2)); //~ ERROR `c2` does not live long enough - c2.v[0].v.set(Some(&c1)); //~ ERROR `c1` does not live long enough + c1.v[0].v.set(Some(&c2)); + c2.v[0].v.set(Some(&c1)); } +//~^ ERROR `c2` does not live long enough +//~| ERROR `c1` does not live long enough fn main() { f(); diff --git a/src/test/ui/span/vec-must-not-hide-type-from-dropck.stderr b/src/test/ui/span/vec-must-not-hide-type-from-dropck.stderr new file mode 100644 index 0000000000..11031ee0ab --- /dev/null +++ b/src/test/ui/span/vec-must-not-hide-type-from-dropck.stderr @@ -0,0 +1,23 @@ +error: `c2` does not live long enough + --> $DIR/vec-must-not-hide-type-from-dropck.rs:129:1 + | +127 | c1.v[0].v.set(Some(&c2)); + | -- borrow occurs here +128 | c2.v[0].v.set(Some(&c1)); +129 | } + | ^ `c2` dropped here while still borrowed + | + = note: values in a scope are dropped in the opposite order they are created + +error: `c1` does not live long enough + --> $DIR/vec-must-not-hide-type-from-dropck.rs:129:1 + | +128 | c2.v[0].v.set(Some(&c1)); + | -- borrow occurs here +129 | } + | ^ `c1` dropped here while still borrowed + | + = note: values in a scope are dropped in the opposite order they are created + +error: aborting due to 2 previous errors + diff --git a/src/test/compile-fail/vec_refs_data_with_early_death.rs b/src/test/ui/span/vec_refs_data_with_early_death.rs similarity index 90% rename from src/test/compile-fail/vec_refs_data_with_early_death.rs rename to src/test/ui/span/vec_refs_data_with_early_death.rs index 0025449a3d..f40a25920b 100644 --- a/src/test/compile-fail/vec_refs_data_with_early_death.rs +++ b/src/test/ui/span/vec_refs_data_with_early_death.rs @@ -24,8 +24,10 @@ fn main() { let x: i8 = 3; let y: i8 = 4; - v.push(&x); //~ ERROR `x` does not live long enough - v.push(&y); //~ ERROR `y` does not live long enough + v.push(&x); + v.push(&y); assert_eq!(v, [&3, &4]); } +//~^ ERROR `x` does not live long enough +//~| ERROR `y` does not live long enough diff --git a/src/test/ui/span/vec_refs_data_with_early_death.stderr b/src/test/ui/span/vec_refs_data_with_early_death.stderr new file mode 100644 index 0000000000..8cc12c32b9 --- /dev/null +++ b/src/test/ui/span/vec_refs_data_with_early_death.stderr @@ -0,0 +1,24 @@ +error: `x` does not live long enough + --> $DIR/vec_refs_data_with_early_death.rs:31:1 + | +27 | v.push(&x); + | - borrow occurs here +... +31 | } + | ^ `x` dropped here while still borrowed + | + = note: values in a scope are dropped in the opposite order they are created + +error: `y` does not live long enough + --> $DIR/vec_refs_data_with_early_death.rs:31:1 + | +28 | v.push(&y); + | - borrow occurs here +... +31 | } + | ^ `y` dropped here while still borrowed + | + = note: values in a scope are dropped in the opposite order they are created + +error: aborting due to 2 previous errors + diff --git a/src/test/compile-fail/wf-method-late-bound-regions.rs b/src/test/ui/span/wf-method-late-bound-regions.rs similarity index 100% rename from src/test/compile-fail/wf-method-late-bound-regions.rs rename to src/test/ui/span/wf-method-late-bound-regions.rs diff --git a/src/test/ui/span/wf-method-late-bound-regions.stderr b/src/test/ui/span/wf-method-late-bound-regions.stderr new file mode 100644 index 0000000000..aeac3102fb --- /dev/null +++ b/src/test/ui/span/wf-method-late-bound-regions.stderr @@ -0,0 +1,13 @@ +error: `pointer` does not live long enough + --> $DIR/wf-method-late-bound-regions.rs:31:5 + | +30 | f2.xmute(&pointer) //~ ERROR `pointer` does not live long enough + | ------- borrow occurs here +31 | }; + | ^ `pointer` dropped here while still borrowed +32 | println!("{}", dangling); +33 | } + | - borrowed value needs to live until here + +error: aborting due to previous error + diff --git a/src/test/ui/update-references.sh b/src/test/ui/update-references.sh index f0a6f8a3d4..aa99d35f7a 100755 --- a/src/test/ui/update-references.sh +++ b/src/test/ui/update-references.sh @@ -36,12 +36,12 @@ while [[ "$1" != "" ]]; do STDOUT_NAME="${1/%.rs/.stdout}" shift if [ -f $BUILD_DIR/$STDOUT_NAME ] && \ - ! (diff $BUILD_DIR/$STDOUT_NAME $MYDIR/$STDOUT_NAME > /dev/null); then + ! (diff $BUILD_DIR/$STDOUT_NAME $MYDIR/$STDOUT_NAME >& /dev/null); then echo updating $MYDIR/$STDOUT_NAME cp $BUILD_DIR/$STDOUT_NAME $MYDIR/$STDOUT_NAME fi if [ -f $BUILD_DIR/$STDERR_NAME ] && \ - ! (diff $BUILD_DIR/$STDERR_NAME $MYDIR/$STDERR_NAME > /dev/null); then + ! (diff $BUILD_DIR/$STDERR_NAME $MYDIR/$STDERR_NAME >& /dev/null); then echo updating $MYDIR/$STDERR_NAME cp $BUILD_DIR/$STDERR_NAME $MYDIR/$STDERR_NAME fi diff --git a/src/tools/cargotest/Cargo.lock b/src/tools/cargotest/Cargo.lock deleted file mode 100644 index bafde903ba..0000000000 --- a/src/tools/cargotest/Cargo.lock +++ /dev/null @@ -1,4 +0,0 @@ -[root] -name = "cargotest" -version = "0.1.0" - diff --git a/src/tools/cargotest/main.rs b/src/tools/cargotest/main.rs index 354cce6912..800186a926 100644 --- a/src/tools/cargotest/main.rs +++ b/src/tools/cargotest/main.rs @@ -24,7 +24,7 @@ struct Test { const TEST_REPOS: &'static [Test] = &[Test { name: "cargo", repo: "https://github.com/rust-lang/cargo", - sha: "d8936af1390ab0844e5e68b459214f2529c9f647", + sha: "806e3c368a15f618244a3b4e918bf77f9c403fd0", lock: None, }, Test { @@ -36,6 +36,20 @@ const TEST_REPOS: &'static [Test] = &[Test { fn main() { + // One of the projects being tested here is Cargo, and when being tested + // Cargo will at some point call `nmake.exe` on Windows MSVC. Unfortunately + // `nmake` will read these two environment variables below and try to + // intepret them. We're likely being run, however, from MSYS `make` which + // uses the same variables. + // + // As a result, to prevent confusion and errors, we remove these variables + // from our environment to prevent passing MSYS make flags to nmake, causing + // it to blow up. + if cfg!(target_env = "msvc") { + env::remove_var("MAKE"); + env::remove_var("MAKEFLAGS"); + } + let args = env::args().collect::>(); let ref cargo = args[1]; let out_dir = Path::new(&args[2]); diff --git a/src/tools/compiletest/Cargo.lock b/src/tools/compiletest/Cargo.lock deleted file mode 100644 index 755697806a..0000000000 --- a/src/tools/compiletest/Cargo.lock +++ /dev/null @@ -1,92 +0,0 @@ -[root] -name = "compiletest" -version = "0.0.0" -dependencies = [ - "env_logger 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)", - "log 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)", - "serialize 0.0.0", -] - -[[package]] -name = "aho-corasick" -version = "0.5.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "memchr 0.1.11 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "env_logger" -version = "0.3.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "log 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)", - "regex 0.1.62 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "libc" -version = "0.2.9" -source = "registry+https://github.com/rust-lang/crates.io-index" - -[[package]] -name = "log" -version = "0.0.0" - -[[package]] -name = "log" -version = "0.3.6" -source = "registry+https://github.com/rust-lang/crates.io-index" - -[[package]] -name = "memchr" -version = "0.1.11" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "libc 0.2.9 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "mempool" -version = "0.3.0" -source = "registry+https://github.com/rust-lang/crates.io-index" - -[[package]] -name = "regex" -version = "0.1.62" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "aho-corasick 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)", - "memchr 0.1.11 (registry+https://github.com/rust-lang/crates.io-index)", - "mempool 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)", - "regex-syntax 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)", - "utf8-ranges 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "regex-syntax" -version = "0.3.1" -source = "registry+https://github.com/rust-lang/crates.io-index" - -[[package]] -name = "serialize" -version = "0.0.0" -dependencies = [ - "log 0.0.0", -] - -[[package]] -name = "utf8-ranges" -version = "0.1.3" -source = "registry+https://github.com/rust-lang/crates.io-index" - -[metadata] -"checksum aho-corasick 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)" = "67077478f0a03952bed2e6786338d400d40c25e9836e08ad50af96607317fd03" -"checksum env_logger 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)" = "aba65b63ffcc17ffacd6cf5aa843da7c5a25e3bd4bbe0b7def8b214e411250e5" -"checksum libc 0.2.9 (registry+https://github.com/rust-lang/crates.io-index)" = "95ca44454e7cfe7f8a2095a41a10c79d96a177c0b1672cbf1a30d901a9c16ee5" -"checksum log 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)" = "ab83497bf8bf4ed2a74259c1c802351fcd67a65baa86394b6ba73c36f4838054" -"checksum memchr 0.1.11 (registry+https://github.com/rust-lang/crates.io-index)" = "d8b629fb514376c675b98c1421e80b151d3817ac42d7c667717d282761418d20" -"checksum mempool 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)" = "f997e65fe3eb7a6f8557a7a477de9ed5c511850c85363d13f7b0145b526ed36a" -"checksum regex 0.1.62 (registry+https://github.com/rust-lang/crates.io-index)" = "22bdab319e36735729aa280752c9293b29ec0053a6810679d697515f80a986fe" -"checksum regex-syntax 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)" = "841591b1e05609a643e3b4d0045fce04f701daba7151ddcd3ad47b080693d5a9" -"checksum utf8-ranges 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)" = "a1ca13c08c41c9c3e04224ed9ff80461d97e121589ff27c753a16cb10830ae0f" diff --git a/src/tools/compiletest/Cargo.toml b/src/tools/compiletest/Cargo.toml index 573ee38886..e05d57365f 100644 --- a/src/tools/compiletest/Cargo.toml +++ b/src/tools/compiletest/Cargo.toml @@ -12,5 +12,5 @@ opt-level = 2 [dependencies] log = "0.3" -env_logger = "0.3" -serialize = { path = "../../libserialize" } \ No newline at end of file +env_logger = { version = "0.3.5", default-features = false } +serialize = { path = "../../libserialize" } diff --git a/src/tools/compiletest/src/common.rs b/src/tools/compiletest/src/common.rs index 5d52273608..34f3837d8b 100644 --- a/src/tools/compiletest/src/common.rs +++ b/src/tools/compiletest/src/common.rs @@ -146,8 +146,14 @@ pub struct Config { // Host triple for the compiler being invoked pub host: String, - // Version of GDB - pub gdb_version: Option, + // Path to / name of the GDB executable + pub gdb: Option, + + // Version of GDB, encoded as ((major * 1000) + minor) * 1000 + patch + pub gdb_version: Option, + + // Whether GDB has native rust support + pub gdb_native_rust: bool, // Version of LLDB pub lldb_version: Option, @@ -183,4 +189,5 @@ pub struct Config { pub cflags: String, pub llvm_components: String, pub llvm_cxxflags: String, + pub nodejs: Option, } diff --git a/src/tools/compiletest/src/header.rs b/src/tools/compiletest/src/header.rs index 503a851676..e57c9949b1 100644 --- a/src/tools/compiletest/src/header.rs +++ b/src/tools/compiletest/src/header.rs @@ -18,6 +18,8 @@ use common::Config; use common; use util; +use extract_gdb_version; + /// Properties which must be known very early, before actually running /// the test. pub struct EarlyProps { @@ -75,7 +77,7 @@ impl EarlyProps { return true; } - if let Some(ref actual_version) = config.gdb_version { + if let Some(actual_version) = config.gdb_version { if line.contains("min-gdb-version") { let min_version = line.trim() .split(' ') @@ -83,7 +85,7 @@ impl EarlyProps { .expect("Malformed GDB version directive"); // Ignore if actual version is smaller the minimum required // version - gdb_version_to_int(actual_version) < gdb_version_to_int(min_version) + actual_version < extract_gdb_version(min_version).unwrap() } else { false } @@ -464,23 +466,6 @@ pub fn parse_name_value_directive(line: &str, directive: &str) -> Option } } -pub fn gdb_version_to_int(version_string: &str) -> isize { - let error_string = format!("Encountered GDB version string with unexpected format: {}", - version_string); - let error_string = error_string; - - let components: Vec<&str> = version_string.trim().split('.').collect(); - - if components.len() != 2 { - panic!("{}", error_string); - } - - let major: isize = components[0].parse().ok().expect(&error_string); - let minor: isize = components[1].parse().ok().expect(&error_string); - - return major * 1000 + minor; -} - pub fn lldb_version_to_int(version_string: &str) -> isize { let error_string = format!("Encountered LLDB version string with unexpected format: {}", version_string); diff --git a/src/tools/compiletest/src/main.rs b/src/tools/compiletest/src/main.rs index cb509044e3..806363679d 100644 --- a/src/tools/compiletest/src/main.rs +++ b/src/tools/compiletest/src/main.rs @@ -12,9 +12,12 @@ #![feature(box_syntax)] #![feature(rustc_private)] +#![feature(static_in_const)] #![feature(test)] #![feature(libc)] +#![cfg_attr(stage0, feature(question_mark))] + #![deny(warnings)] extern crate libc; @@ -33,6 +36,7 @@ use std::ffi::OsString; use std::fs; use std::io; use std::path::{Path, PathBuf}; +use std::process::Command; use getopts::{optopt, optflag, reqopt}; use common::Config; use common::{Pretty, DebugInfoGdb, DebugInfoLldb, Mode}; @@ -71,7 +75,7 @@ fn main() { pub fn parse_config(args: Vec ) -> Config { let groups : Vec = - vec!(reqopt("", "compile-lib-path", "path to host shared libraries", "PATH"), + 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"), @@ -96,7 +100,7 @@ pub fn parse_config(args: Vec ) -> Config { optopt("", "logfile", "file to log test execution to", "FILE"), optopt("", "target", "the target to build for", "TARGET"), optopt("", "host", "the host to build for", "HOST"), - optopt("", "gdb-version", "the version of GDB used", "VERSION STRING"), + optopt("", "gdb", "path to GDB to use for GDB debuginfo tests", "PATH"), optopt("", "lldb-version", "the version of LLDB used", "VERSION STRING"), optopt("", "llvm-version", "the version of LLVM used", "VERSION STRING"), optopt("", "android-cross-path", "Android NDK standalone path", "PATH"), @@ -108,7 +112,8 @@ pub fn parse_config(args: Vec ) -> Config { reqopt("", "cflags", "flags for the C compiler", "FLAGS"), reqopt("", "llvm-components", "list of LLVM components built in", "LIST"), reqopt("", "llvm-cxxflags", "C++ flags for LLVM", "FLAGS"), - optflag("h", "help", "show this message")); + optopt("", "nodejs", "the name of nodejs", "PATH"), + optflag("h", "help", "show this message")]; let (argv0, args_) = args.split_first().unwrap(); if args.len() == 1 || args[1] == "-h" || args[1] == "--help" { @@ -146,6 +151,8 @@ pub fn parse_config(args: Vec ) -> Config { } } + let (gdb, gdb_version, gdb_native_rust) = analyze_gdb(matches.opt_str("gdb")); + Config { compile_lib_path: make_absolute(opt_path(matches, "compile-lib-path")), run_lib_path: make_absolute(opt_path(matches, "run-lib-path")), @@ -168,7 +175,9 @@ pub fn parse_config(args: Vec ) -> Config { target_rustcflags: matches.opt_str("target-rustcflags"), target: opt_str2(matches.opt_str("target")), host: opt_str2(matches.opt_str("host")), - gdb_version: extract_gdb_version(matches.opt_str("gdb-version")), + gdb: gdb, + gdb_version: gdb_version, + gdb_native_rust: gdb_native_rust, lldb_version: extract_lldb_version(matches.opt_str("lldb-version")), llvm_version: matches.opt_str("llvm-version"), android_cross_path: opt_path(matches, "android-cross-path"), @@ -189,6 +198,7 @@ pub fn parse_config(args: Vec ) -> Config { cflags: matches.opt_str("cflags").unwrap(), llvm_components: matches.opt_str("llvm-components").unwrap(), llvm_cxxflags: matches.opt_str("llvm-cxxflags").unwrap(), + nodejs: matches.opt_str("nodejs"), } } @@ -312,6 +322,7 @@ pub fn test_opts(config: &Config) -> test::TestOpts { }, color: test::AutoColor, test_threads: None, + skip: vec![], } } @@ -429,10 +440,17 @@ pub fn make_test(config: &Config, testpaths: &TestPaths) -> test::TestDescAndFn } }; + // Debugging emscripten code doesn't make sense today + let mut ignore = early_props.ignore; + if (config.mode == DebugInfoGdb || config.mode == DebugInfoLldb) && + config.target.contains("emscripten") { + ignore = true; + } + test::TestDescAndFn { desc: test::TestDesc { name: make_test_name(config, testpaths), - ignore: early_props.ignore, + ignore: ignore, should_panic: should_panic, }, testfn: make_test_closure(config, testpaths), @@ -453,49 +471,101 @@ pub fn make_test_name(config: &Config, testpaths: &TestPaths) -> test::TestName pub fn make_test_closure(config: &Config, testpaths: &TestPaths) -> test::TestFn { let config = config.clone(); let testpaths = testpaths.clone(); - test::DynTestFn(Box::new(move || { + test::DynTestFn(Box::new(move |()| { runtest::run(config, &testpaths) })) } -fn extract_gdb_version(full_version_line: Option) -> Option { - match full_version_line { - Some(ref full_version_line) - if !full_version_line.trim().is_empty() => { - let full_version_line = full_version_line.trim(); +/// Returns (Path to GDB, GDB Version, GDB has Rust Support) +fn analyze_gdb(gdb: Option) -> (Option, Option, bool) { + #[cfg(not(windows))] + const GDB_FALLBACK: &str = "gdb"; + #[cfg(windows)] + const GDB_FALLBACK: &str = "gdb.exe"; - // used to be a regex "(^|[^0-9])([0-9]\.[0-9]+)" - for (pos, c) in full_version_line.char_indices() { - if !c.is_digit(10) { - continue - } - if pos + 2 >= full_version_line.len() { - continue - } - if full_version_line[pos + 1..].chars().next().unwrap() != '.' { - continue - } - if !full_version_line[pos + 2..].chars().next().unwrap().is_digit(10) { - continue - } - if pos > 0 && full_version_line[..pos].chars().next_back() - .unwrap().is_digit(10) { - continue - } - let mut end = pos + 3; - while end < full_version_line.len() && - full_version_line[end..].chars().next() - .unwrap().is_digit(10) { - end += 1; - } - return Some(full_version_line[pos..end].to_owned()); - } - println!("Could not extract GDB version from line '{}'", - full_version_line); - None - }, - _ => None + const MIN_GDB_WITH_RUST: u32 = 7011010; + + let gdb = match gdb { + None => GDB_FALLBACK, + Some(ref s) if s.is_empty() => GDB_FALLBACK, // may be empty if configure found no gdb + Some(ref s) => s, + }; + + let version_line = Command::new(gdb).arg("--version").output().map(|output| { + String::from_utf8_lossy(&output.stdout).lines().next().unwrap().to_string() + }).ok(); + + let version = match version_line { + Some(line) => extract_gdb_version(&line), + None => return (None, None, false), + }; + + let gdb_native_rust = version.map_or(false, |v| v >= MIN_GDB_WITH_RUST); + + return (Some(gdb.to_owned()), version, gdb_native_rust); +} + +fn extract_gdb_version(full_version_line: &str) -> Option { + let full_version_line = full_version_line.trim(); + + // GDB versions look like this: "major.minor.patch?.yyyymmdd?", with both + // of the ? sections being optional + + // We will parse up to 3 digits for minor and patch, ignoring the date + // We limit major to 1 digit, otherwise, on openSUSE, we parse the openSUSE version + + // don't start parsing in the middle of a number + let mut prev_was_digit = false; + for (pos, c) in full_version_line.char_indices() { + if prev_was_digit || !c.is_digit(10) { + prev_was_digit = c.is_digit(10); + continue + } + + prev_was_digit = true; + + let line = &full_version_line[pos..]; + + let next_split = match line.find(|c: char| !c.is_digit(10)) { + Some(idx) => idx, + None => continue, // no minor version + }; + + if line.as_bytes()[next_split] != b'.' { + continue; // no minor version + } + + let major = &line[..next_split]; + let line = &line[next_split + 1..]; + + let (minor, patch) = match line.find(|c: char| !c.is_digit(10)) { + Some(idx) => if line.as_bytes()[idx] == b'.' { + let patch = &line[idx + 1..]; + + let patch_len = patch.find(|c: char| !c.is_digit(10)).unwrap_or(patch.len()); + let patch = &patch[..patch_len]; + let patch = if patch_len > 3 || patch_len == 0 { None } else { Some(patch) }; + + (&line[..idx], patch) + } else { + (&line[..idx], None) + }, + None => (line, None), + }; + + if major.len() != 1 || minor.is_empty() { + continue; + } + + let major: u32 = major.parse().unwrap(); + let minor: u32 = minor.parse().unwrap(); + let patch: u32 = patch.unwrap_or("0").parse().unwrap(); + + return Some(((major * 1000) + minor) * 1000 + patch); } + + println!("Could not extract GDB version from line '{}'", full_version_line); + None } fn extract_lldb_version(full_version_line: Option) -> Option { @@ -541,3 +611,44 @@ fn extract_lldb_version(full_version_line: Option) -> Option { fn is_blacklisted_lldb_version(version: &str) -> bool { version == "350" } + +#[test] +fn test_extract_gdb_version() { + macro_rules! test { ($($expectation:tt: $input:tt,)*) => {{$( + assert_eq!(extract_gdb_version($input), Some($expectation)); + )*}}} + + test! { + 7000001: "GNU gdb (GDB) CentOS (7.0.1-45.el5.centos)", + + 7002000: "GNU gdb (GDB) Red Hat Enterprise Linux (7.2-90.el6)", + + 7004000: "GNU gdb (Ubuntu/Linaro 7.4-2012.04-0ubuntu2.1) 7.4-2012.04", + 7004001: "GNU gdb (GDB) 7.4.1-debian", + + 7006001: "GNU gdb (GDB) Red Hat Enterprise Linux 7.6.1-80.el7", + + 7007001: "GNU gdb (Ubuntu 7.7.1-0ubuntu5~14.04.2) 7.7.1", + 7007001: "GNU gdb (Debian 7.7.1+dfsg-5) 7.7.1", + 7007001: "GNU gdb (GDB) Fedora 7.7.1-21.fc20", + + 7008000: "GNU gdb (GDB; openSUSE 13.2) 7.8", + 7009001: "GNU gdb (GDB) Fedora 7.9.1-20.fc22", + 7010001: "GNU gdb (GDB) Fedora 7.10.1-31.fc23", + + 7011000: "GNU gdb (Ubuntu 7.11-0ubuntu1) 7.11", + 7011001: "GNU gdb (Ubuntu 7.11.1-0ubuntu1~16.04) 7.11.1", + 7011001: "GNU gdb (Debian 7.11.1-2) 7.11.1", + 7011001: "GNU gdb (GDB) Fedora 7.11.1-86.fc24", + 7011001: "GNU gdb (GDB; openSUSE Leap 42.1) 7.11.1", + 7011001: "GNU gdb (GDB; openSUSE Tumbleweed) 7.11.1", + + 7011090: "7.11.90", + 7011090: "GNU gdb (Ubuntu 7.11.90.20161005-0ubuntu1) 7.11.90.20161005-git", + + 7012000: "7.12", + 7012000: "GNU gdb (GDB) 7.12", + 7012000: "GNU gdb (GDB) 7.12.20161027-git", + 7012050: "GNU gdb (GDB) 7.12.50.20161027-git", + } +} diff --git a/src/tools/compiletest/src/runtest.rs b/src/tools/compiletest/src/runtest.rs index 8fdb882164..8cb2e3b1c2 100644 --- a/src/tools/compiletest/src/runtest.rs +++ b/src/tools/compiletest/src/runtest.rs @@ -32,6 +32,8 @@ use std::path::{Path, PathBuf}; use std::process::{Command, Output, ExitStatus}; use std::str; +use extract_gdb_version; + pub fn run(config: Config, testpaths: &TestPaths) { match &*config.target { @@ -41,7 +43,12 @@ pub fn run(config: Config, testpaths: &TestPaths) { } } - _=> { } + _ => { + // android has it's own gdb handling + if config.mode == DebugInfoGdb && config.gdb.is_none() { + panic!("gdb not available but debuginfo gdb debuginfo test requested"); + } + } } if config.verbose { @@ -253,7 +260,7 @@ impl<'test> TestCx<'test> { let mut src = String::new(); File::open(&self.testpaths.file).unwrap().read_to_string(&mut src).unwrap(); - let mut srcs = vec!(src); + let mut srcs = vec![src]; let mut round = 0; while round < rounds { @@ -335,13 +342,13 @@ impl<'test> TestCx<'test> { -> ProcArgs { let aux_dir = self.aux_output_dir_name(); // FIXME (#9639): This needs to handle non-utf8 paths - let mut args = vec!("-".to_owned(), + let mut args = vec!["-".to_owned(), "-Zunstable-options".to_owned(), "--unpretty".to_owned(), pretty_type, format!("--target={}", self.config.target), "-L".to_owned(), - aux_dir.to_str().unwrap().to_owned()); + aux_dir.to_str().unwrap().to_owned()]; args.extend(self.split_maybe_args(&self.config.target_rustcflags)); args.extend(self.props.compile_flags.iter().cloned()); return ProcArgs { @@ -388,7 +395,7 @@ actual:\n\ self.create_dir_racy(&out_dir); // FIXME (#9639): This needs to handle non-utf8 paths - let mut args = vec!("-".to_owned(), + let mut args = vec!["-".to_owned(), "-Zno-trans".to_owned(), "--out-dir".to_owned(), out_dir.to_str().unwrap().to_owned(), @@ -396,7 +403,7 @@ actual:\n\ "-L".to_owned(), self.config.build_base.to_str().unwrap().to_owned(), "-L".to_owned(), - aux_dir.to_str().unwrap().to_owned()); + aux_dir.to_str().unwrap().to_owned()]; if let Some(revision) = self.revision { args.extend(vec![ format!("--cfg"), @@ -430,11 +437,23 @@ actual:\n\ } fn run_debuginfo_gdb_test_no_opt(&self) { + let prefixes = if self.config.gdb_native_rust { + // GDB with Rust + static PREFIXES: &'static [&'static str] = &["gdb", "gdbr"]; + println!("NOTE: compiletest thinks it is using GDB with native rust support"); + PREFIXES + } else { + // Generic GDB + static PREFIXES: &'static [&'static str] = &["gdb", "gdbg"]; + println!("NOTE: compiletest thinks it is using GDB without native rust support"); + PREFIXES + }; + let DebuggerCommands { commands, check_lines, breakpoint_lines - } = self.parse_debugger_commands("gdb"); + } = self.parse_debugger_commands(prefixes); let mut cmds = commands.join("\n"); // compile test file (it should have 'compile-flags:-g' in the header) @@ -487,7 +506,7 @@ actual:\n\ exe_file.to_str().unwrap().to_owned(), self.config.adb_test_dir.clone() ], - vec!(("".to_owned(), "".to_owned())), + vec![("".to_owned(), "".to_owned())], Some("".to_owned())) .expect(&format!("failed to exec `{:?}`", self.config.adb_path)); @@ -499,7 +518,7 @@ actual:\n\ "tcp:5039".to_owned(), "tcp:5039".to_owned() ], - vec!(("".to_owned(), "".to_owned())), + vec![("".to_owned(), "".to_owned())], Some("".to_owned())) .expect(&format!("failed to exec `{:?}`", self.config.adb_path)); @@ -520,8 +539,8 @@ actual:\n\ "shell".to_owned(), adb_arg.clone() ], - vec!(("".to_owned(), - "".to_owned())), + vec![("".to_owned(), + "".to_owned())], Some("".to_owned())) .expect(&format!("failed to exec `{:?}`", self.config.adb_path)); loop { @@ -535,10 +554,10 @@ actual:\n\ let debugger_script = self.make_out_name("debugger.script"); // FIXME (#9639): This needs to handle non-utf8 paths let debugger_opts = - vec!("-quiet".to_owned(), + vec!["-quiet".to_owned(), "-batch".to_owned(), "-nx".to_owned(), - format!("-command={}", debugger_script.to_str().unwrap())); + format!("-command={}", debugger_script.to_str().unwrap())]; let mut gdb_path = tool_path; gdb_path.push_str(&format!("/bin/{}-gdb", self.config.target)); @@ -550,7 +569,7 @@ actual:\n\ &gdb_path, None, &debugger_opts, - vec!(("".to_owned(), "".to_owned())), + vec![("".to_owned(), "".to_owned())], None) .expect(&format!("failed to exec `{:?}`", gdb_path)); let cmdline = { @@ -586,19 +605,18 @@ actual:\n\ script_str.push_str("show version\n"); match self.config.gdb_version { - Some(ref version) => { + Some(version) => { println!("NOTE: compiletest thinks it is using GDB version {}", version); - if header::gdb_version_to_int(version) > - header::gdb_version_to_int("7.4") { - // Add the directory containing the pretty printers to - // GDB's script auto loading safe path - script_str.push_str( - &format!("add-auto-load-safe-path {}\n", - rust_pp_module_abs_path.replace(r"\", r"\\")) - ); - } + if version > extract_gdb_version("7.4").unwrap() { + // Add the directory containing the pretty printers to + // GDB's script auto loading safe path + script_str.push_str( + &format!("add-auto-load-safe-path {}\n", + rust_pp_module_abs_path.replace(r"\", r"\\")) + ); + } } _ => { println!("NOTE: compiletest does not know which version of \ @@ -633,22 +651,17 @@ actual:\n\ debug!("script_str = {}", script_str); self.dump_output_file(&script_str, "debugger.script"); - // run debugger script with gdb - fn debugger() -> &'static str { - if cfg!(windows) {"gdb.exe"} else {"gdb"} - } - let debugger_script = self.make_out_name("debugger.script"); // FIXME (#9639): This needs to handle non-utf8 paths let debugger_opts = - vec!("-quiet".to_owned(), + vec!["-quiet".to_owned(), "-batch".to_owned(), "-nx".to_owned(), - format!("-command={}", debugger_script.to_str().unwrap())); + format!("-command={}", debugger_script.to_str().unwrap())]; let proc_args = ProcArgs { - prog: debugger().to_owned(), + prog: self.config.gdb.as_ref().unwrap().to_owned(), args: debugger_opts, }; @@ -731,7 +744,7 @@ actual:\n\ check_lines, breakpoint_lines, .. - } = self.parse_debugger_commands("lldb"); + } = self.parse_debugger_commands(&["lldb"]); // Write debugger script: // We don't want to hang when calling `quit` while the process is still running @@ -826,13 +839,15 @@ actual:\n\ } } - fn parse_debugger_commands(&self, debugger_prefix: &str) -> DebuggerCommands { - let command_directive = format!("{}-command", debugger_prefix); - let check_directive = format!("{}-check", debugger_prefix); + fn parse_debugger_commands(&self, debugger_prefixes: &[&str]) -> DebuggerCommands { + let directives = debugger_prefixes.iter().map(|prefix| ( + format!("{}-command", prefix), + format!("{}-check", prefix), + )).collect::>(); - let mut breakpoint_lines = vec!(); - let mut commands = vec!(); - let mut check_lines = vec!(); + let mut breakpoint_lines = vec![]; + let mut commands = vec![]; + let mut check_lines = vec![]; let mut counter = 1; let reader = BufReader::new(File::open(&self.testpaths.file).unwrap()); for line in reader.lines() { @@ -842,17 +857,19 @@ actual:\n\ breakpoint_lines.push(counter); } - header::parse_name_value_directive( - &line, - &command_directive).map(|cmd| { - commands.push(cmd) - }); - - header::parse_name_value_directive( - &line, - &check_directive).map(|cmd| { - check_lines.push(cmd) - }); + for &(ref command_directive, ref check_directive) in &directives { + header::parse_name_value_directive( + &line, + &command_directive).map(|cmd| { + commands.push(cmd) + }); + + header::parse_name_value_directive( + &line, + &check_directive).map(|cmd| { + check_lines.push(cmd) + }); + } } Err(e) => { self.fatal(&format!("Error while parsing debugger commands: {}", e)) @@ -1120,8 +1137,8 @@ actual:\n\ fn compile_test(&self) -> ProcRes { let aux_dir = self.aux_output_dir_name(); // FIXME (#9639): This needs to handle non-utf8 paths - let link_args = vec!("-L".to_owned(), - aux_dir.to_str().unwrap().to_owned()); + let link_args = vec!["-L".to_owned(), + aux_dir.to_str().unwrap().to_owned()]; let args = self.make_compile_args(link_args, &self.testpaths.file, TargetLocation::ThisFile(self.make_exe_name())); @@ -1168,7 +1185,6 @@ actual:\n\ "arm-linux-androideabi" | "armv7-linux-androideabi" | "aarch64-linux-android" => { self._arm_exec_compiled_test(env) } - _=> { let aux_dir = self.aux_output_dir_name(); self.compose_and_run(self.make_run_args(), @@ -1232,9 +1248,9 @@ actual:\n\ if (self.config.target.contains("musl") && !aux_props.force_host) || self.config.target.contains("emscripten") { - vec!("--crate-type=lib".to_owned()) + vec!["--crate-type=lib".to_owned()] } else { - vec!("--crate-type=dylib".to_owned()) + vec!["--crate-type=dylib".to_owned()] } }; crate_type.extend(extra_link_args.clone()); @@ -1316,10 +1332,10 @@ actual:\n\ }; // FIXME (#9639): This needs to handle non-utf8 paths - let mut args = vec!(input_file.to_str().unwrap().to_owned(), + let mut args = vec![input_file.to_str().unwrap().to_owned(), "-L".to_owned(), self.config.build_base.to_str().unwrap().to_owned(), - format!("--target={}", target)); + format!("--target={}", target)]; if let Some(revision) = self.revision { args.extend(vec![ @@ -1421,7 +1437,7 @@ actual:\n\ fn make_exe_name(&self) -> PathBuf { let mut f = self.output_base_name(); // FIXME: This is using the host architecture exe suffix, not target! - if self.config.target == "asmjs-unknown-emscripten" { + if self.config.target.contains("emscripten") { let mut fname = f.file_name().unwrap().to_os_string(); fname.push(".js"); f.set_file_name(&fname); @@ -1439,8 +1455,9 @@ actual:\n\ let mut args = self.split_maybe_args(&self.config.runtool); // If this is emscripten, then run tests under nodejs - if self.config.target == "asmjs-unknown-emscripten" { - args.push("nodejs".to_owned()); + if self.config.target.contains("emscripten") { + let nodejs = self.config.nodejs.clone().unwrap_or("nodejs".to_string()); + args.push(nodejs); } let exe_file = self.make_exe_name(); @@ -1613,7 +1630,7 @@ actual:\n\ args.prog.clone(), self.config.adb_test_dir.clone() ], - vec!(("".to_owned(), "".to_owned())), + vec![("".to_owned(), "".to_owned())], Some("".to_owned())) .expect(&format!("failed to exec `{}`", self.config.adb_path)); @@ -1645,7 +1662,7 @@ actual:\n\ &self.config.adb_path, None, &runargs, - vec!(("".to_owned(), "".to_owned())), Some("".to_owned())) + vec![("".to_owned(), "".to_owned())], Some("".to_owned())) .expect(&format!("failed to exec `{}`", self.config.adb_path)); // get exitcode of result @@ -1659,7 +1676,7 @@ actual:\n\ &self.config.adb_path, None, &runargs, - vec!(("".to_owned(), "".to_owned())), + vec![("".to_owned(), "".to_owned())], Some("".to_owned())) .expect(&format!("failed to exec `{}`", self.config.adb_path)); @@ -1683,7 +1700,7 @@ actual:\n\ &self.config.adb_path, None, &runargs, - vec!(("".to_owned(), "".to_owned())), + vec![("".to_owned(), "".to_owned())], Some("".to_owned())) .expect(&format!("failed to exec `{}`", self.config.adb_path)); @@ -1698,7 +1715,7 @@ actual:\n\ &self.config.adb_path, None, &runargs, - vec!(("".to_owned(), "".to_owned())), + vec![("".to_owned(), "".to_owned())], Some("".to_owned())) .expect(&format!("failed to exec `{}`", self.config.adb_path)); @@ -1730,8 +1747,8 @@ actual:\n\ .to_owned(), self.config.adb_test_dir.to_owned(), ], - vec!(("".to_owned(), - "".to_owned())), + vec![("".to_owned(), + "".to_owned())], Some("".to_owned())) .expect(&format!("failed to exec `{}`", self.config.adb_path)); @@ -1749,9 +1766,9 @@ actual:\n\ fn compile_test_and_save_ir(&self) -> ProcRes { let aux_dir = self.aux_output_dir_name(); // FIXME (#9639): This needs to handle non-utf8 paths - let mut link_args = vec!("-L".to_owned(), - aux_dir.to_str().unwrap().to_owned()); - let llvm_args = vec!("--emit=llvm-ir".to_owned(),); + let mut link_args = vec!["-L".to_owned(), + aux_dir.to_str().unwrap().to_owned()]; + let llvm_args = vec!["--emit=llvm-ir".to_owned(),]; link_args.extend(llvm_args); let args = self.make_compile_args(link_args, &self.testpaths.file, @@ -1768,8 +1785,8 @@ actual:\n\ let proc_args = ProcArgs { // FIXME (#9639): This needs to handle non-utf8 paths prog: prog.to_str().unwrap().to_owned(), - args: vec!(format!("-input-file={}", irfile.to_str().unwrap()), - self.testpaths.file.to_str().unwrap().to_owned()) + args: vec![format!("-input-file={}", irfile.to_str().unwrap()), + self.testpaths.file.to_str().unwrap().to_owned()] }; self.compose_and_run(proc_args, Vec::new(), "", None, None) } @@ -2105,12 +2122,17 @@ actual:\n\ .collect::>().join(" "); cmd.env("IS_MSVC", "1") + .env("IS_WINDOWS", "1") .env("MSVC_LIB", format!("'{}' -nologo", lib.display())) .env("CC", format!("'{}' {}", self.config.cc, cflags)) .env("CXX", &self.config.cxx); } else { cmd.env("CC", format!("{} {}", self.config.cc, self.config.cflags)) .env("CXX", format!("{} {}", self.config.cxx, self.config.cflags)); + + if self.config.target.contains("windows") { + cmd.env("IS_WINDOWS", "1"); + } } let output = cmd.output().expect("failed to spawn `make`"); diff --git a/src/tools/compiletest/src/util.rs b/src/tools/compiletest/src/util.rs index 428bbcfe57..cad71c59f0 100644 --- a/src/tools/compiletest/src/util.rs +++ b/src/tools/compiletest/src/util.rs @@ -43,7 +43,8 @@ const ARCH_TABLE: &'static [(&'static str, &'static str)] = &[("aarch64", "aarch ("sparc", "sparc"), ("x86_64", "x86_64"), ("xcore", "xcore"), - ("asmjs", "asmjs")]; + ("asmjs", "asmjs"), + ("wasm32", "wasm32")]; pub fn get_os(triple: &str) -> &'static str { for &(triple_os, os) in OS_TABLE { diff --git a/src/tools/error_index_generator/Cargo.lock b/src/tools/error_index_generator/Cargo.lock deleted file mode 100644 index b7d2cfcaaa..0000000000 --- a/src/tools/error_index_generator/Cargo.lock +++ /dev/null @@ -1,4 +0,0 @@ -[root] -name = "error_index_generator" -version = "0.0.0" - diff --git a/src/tools/error_index_generator/main.rs b/src/tools/error_index_generator/main.rs index 7bdf1343aa..e33df0dfbc 100644 --- a/src/tools/error_index_generator/main.rs +++ b/src/tools/error_index_generator/main.rs @@ -24,7 +24,7 @@ use std::path::PathBuf; use syntax::diagnostics::metadata::{get_metadata_dir, ErrorMetadataMap, ErrorMetadata}; -use rustdoc::html::markdown::Markdown; +use rustdoc::html::markdown::{Markdown, PLAYGROUND}; use rustc_serialize::json; enum OutputFormat { @@ -201,6 +201,9 @@ fn parse_args() -> (OutputFormat, PathBuf) { } fn main() { + PLAYGROUND.with(|slot| { + *slot.borrow_mut() = Some((None, String::from("https://play.rust-lang.org/"))); + }); let (format, dst) = parse_args(); if let Err(e) = main_with_result(format, &dst) { panic!("{}", e.description()); diff --git a/src/tools/linkchecker/Cargo.lock b/src/tools/linkchecker/Cargo.lock deleted file mode 100644 index d71df6d3f8..0000000000 --- a/src/tools/linkchecker/Cargo.lock +++ /dev/null @@ -1,50 +0,0 @@ -[root] -name = "linkchecker" -version = "0.1.0" -dependencies = [ - "url 1.2.0 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "idna" -version = "0.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "matches 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)", - "unicode-bidi 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)", - "unicode-normalization 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "matches" -version = "0.1.2" -source = "registry+https://github.com/rust-lang/crates.io-index" - -[[package]] -name = "unicode-bidi" -version = "0.2.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "matches 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "unicode-normalization" -version = "0.1.2" -source = "registry+https://github.com/rust-lang/crates.io-index" - -[[package]] -name = "url" -version = "1.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "idna 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)", - "matches 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[metadata] -"checksum idna 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "1053236e00ce4f668aeca4a769a09b3bf5a682d802abd6f3cb39374f6b162c11" -"checksum matches 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)" = "15305656809ce5a4805b1ff2946892810992197ce1270ff79baded852187942e" -"checksum unicode-bidi 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)" = "c1f7ceb96afdfeedee42bade65a0d585a6a0106f681b6749c8ff4daa8df30b3f" -"checksum unicode-normalization 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)" = "26643a2f83bac55f1976fb716c10234485f9202dcd65cfbdf9da49867b271172" -"checksum url 1.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "afe9ec54bc4db14bc8744b7fed060d785ac756791450959b2248443319d5b119" diff --git a/src/tools/rustbook/Cargo.lock b/src/tools/rustbook/Cargo.lock deleted file mode 100644 index e541ce4b2b..0000000000 --- a/src/tools/rustbook/Cargo.lock +++ /dev/null @@ -1,4 +0,0 @@ -[root] -name = "rustbook" -version = "0.0.0" - diff --git a/src/tools/rustbook/book.rs b/src/tools/rustbook/book.rs index 36a37dba1f..c5f72127a9 100644 --- a/src/tools/rustbook/book.rs +++ b/src/tools/rustbook/book.rs @@ -94,16 +94,16 @@ pub fn parse_summary(input: &mut Read, src: &Path) -> Result> } } - let mut top_items = vec!(); - let mut stack = vec!(); - let mut errors = vec!(); + let mut top_items = vec![]; + let mut stack = vec![]; + let mut errors = vec![]; // always include the introduction top_items.push(BookItem { title: "Introduction".to_string(), path: PathBuf::from("README.md"), path_to_root: PathBuf::from(""), - children: vec!(), + children: vec![], }); for line_result in BufReader::new(input).lines() { @@ -142,7 +142,7 @@ pub fn parse_summary(input: &mut Read, src: &Path) -> Result> title: title, path: path_from_root, path_to_root: path_to_root, - children: vec!(), + children: vec![], }; let level = indent.chars().map(|c| -> usize { match c { diff --git a/src/tools/rustbook/build.rs b/src/tools/rustbook/build.rs index 09c2d2510e..d88ff48843 100644 --- a/src/tools/rustbook/build.rs +++ b/src/tools/rustbook/build.rs @@ -131,7 +131,6 @@ fn render(book: &Book, tgt: &Path) -> CliResult<()> { { let mut buffer = BufWriter::new(File::create(&postlude)?); writeln!(&mut buffer, "")?; - writeln!(&mut buffer, "")?; writeln!(&mut buffer, "")?; } @@ -143,7 +142,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=https://play.rust-lang.org"), + format!("--markdown-playground-url=https://play.rust-lang.org/"), format!("--markdown-css={}", item.path_to_root.join("rustbook.css").display()), "--markdown-no-toc".to_string(), ]; @@ -158,10 +157,6 @@ fn render(book: &Book, tgt: &Path) -> CliResult<()> { // create index.html from the root README fs::copy(&tgt.join("README.html"), &tgt.join("index.html"))?; - // Copy js for playpen - let mut playpen = File::create(tgt.join("playpen.js"))?; - let js = include_bytes!("../../librustdoc/html/static/playpen.js"); - playpen.write_all(js)?; Ok(()) } diff --git a/src/tools/tidy/Cargo.lock b/src/tools/tidy/Cargo.lock deleted file mode 100644 index acaf9e5550..0000000000 --- a/src/tools/tidy/Cargo.lock +++ /dev/null @@ -1,4 +0,0 @@ -[root] -name = "tidy" -version = "0.1.0" - diff --git a/src/tools/tidy/src/bins.rs b/src/tools/tidy/src/bins.rs index ea274266f1..ef93b0858b 100644 --- a/src/tools/tidy/src/bins.rs +++ b/src/tools/tidy/src/bins.rs @@ -44,28 +44,27 @@ pub fn check(path: &Path, bad: &mut bool) { let filename = file.file_name().unwrap().to_string_lossy(); let extensions = [".py", ".sh"]; if extensions.iter().any(|e| filename.ends_with(e)) { - return + return; } let metadata = t!(fs::symlink_metadata(&file), &file); if metadata.mode() & 0o111 != 0 { let rel_path = file.strip_prefix(path).unwrap(); let git_friendly_path = rel_path.to_str().unwrap().replace("\\", "/"); - let ret_code = Command::new("git") - .arg("ls-files") - .arg(&git_friendly_path) - .current_dir(path) - .stdout(Stdio::null()) - .stderr(Stdio::null()) - .status() - .unwrap_or_else(|e| { - panic!("could not run git ls-files: {}", e); - }); - if ret_code.success() { + let output = Command::new("git") + .arg("ls-files") + .arg(&git_friendly_path) + .current_dir(path) + .stderr(Stdio::null()) + .output() + .unwrap_or_else(|e| { + panic!("could not run git ls-files: {}", e); + }); + let path_bytes = rel_path.as_os_str().as_bytes(); + if output.status.success() && output.stdout.starts_with(path_bytes) { println!("binary checked into source: {}", file.display()); *bad = true; } } }) } - diff --git a/src/tools/tidy/src/cargo.rs b/src/tools/tidy/src/cargo.rs index 4932fd5147..a7784e65c5 100644 --- a/src/tools/tidy/src/cargo.rs +++ b/src/tools/tidy/src/cargo.rs @@ -88,9 +88,11 @@ fn verify(tomlfile: &Path, libfile: &Path, bad: &mut bool) { continue } - // We want the compiler to depend on the proc_macro crate so that it is built and - // included in the end, but we don't want to actually use it in the compiler. - if toml.contains("name = \"rustc_driver\"") && krate == "proc_macro" { + // We want the compiler to depend on the proc_macro_plugin crate so + // that it is built and included in the end, but we don't want to + // actually use it in the compiler. + if toml.contains("name = \"rustc_driver\"") && + krate == "proc_macro_plugin" { continue } diff --git a/src/tools/tidy/src/features.rs b/src/tools/tidy/src/features.rs index 199e8a77df..4ef07f7e4b 100644 --- a/src/tools/tidy/src/features.rs +++ b/src/tools/tidy/src/features.rs @@ -18,27 +18,42 @@ //! * Library features have at most one `since` value use std::collections::HashMap; +use std::fmt; use std::fs::File; use std::io::prelude::*; use std::path::Path; -const STATUSES: &'static [&'static str] = &[ - "Active", "Deprecated", "Removed", "Accepted", -]; +#[derive(PartialEq)] +enum Status { + Stable, + Unstable, +} + +impl fmt::Display for Status { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + let as_str = match *self { + Status::Stable => "stable", + Status::Unstable => "unstable", + }; + fmt::Display::fmt(as_str, f) + } +} + struct Feature { name: String, + level: Status, since: String, - status: String, } struct LibFeature { - level: String, + level: Status, since: String, } pub fn check(path: &Path, bad: &mut bool) { let features = collect_lang_features(&path.join("libsyntax/feature_gate.rs")); + assert!(!features.is_empty()); let mut lib_features = HashMap::::new(); let mut contents = String::new(); @@ -48,7 +63,7 @@ pub fn check(path: &Path, bad: &mut bool) { let filename = file.file_name().unwrap().to_string_lossy(); if !filename.ends_with(".rs") || filename == "features.rs" || filename == "diagnostic_list.rs" { - return + return; } contents.truncate(0); @@ -60,24 +75,24 @@ pub fn check(path: &Path, bad: &mut bool) { *bad = true; }; let level = if line.contains("[unstable(") { - "unstable" + Status::Unstable } else if line.contains("[stable(") { - "stable" + Status::Stable } else { - continue + continue; }; let feature_name = match find_attr_val(line, "feature") { Some(name) => name, None => { err("malformed stability attribute"); - continue + continue; } }; let since = match find_attr_val(line, "since") { Some(name) => name, - None if level == "stable" => { + None if level == Status::Stable => { err("malformed stability attribute"); - continue + continue; } None => "None", }; @@ -92,27 +107,34 @@ pub fn check(path: &Path, bad: &mut bool) { if s.since != since { err("different `since` than before"); } - continue + continue; } - lib_features.insert(feature_name.to_owned(), LibFeature { - level: level.to_owned(), - since: since.to_owned(), - }); + lib_features.insert(feature_name.to_owned(), + LibFeature { + level: level, + since: since.to_owned(), + }); } }); if *bad { - return + return; } let mut lines = Vec::new(); for feature in features { lines.push(format!("{:<32} {:<8} {:<12} {:<8}", - feature.name, "lang", feature.status, feature.since)); + feature.name, + "lang", + feature.level, + feature.since)); } for (name, feature) in lib_features { lines.push(format!("{:<32} {:<8} {:<12} {:<8}", - name, "lib", feature.level, feature.since)); + name, + "lib", + feature.level, + feature.since)); } lines.sort(); @@ -122,39 +144,32 @@ pub fn check(path: &Path, bad: &mut bool) { } fn find_attr_val<'a>(line: &'a str, attr: &str) -> Option<&'a str> { - line.find(attr).and_then(|i| { - line[i..].find("\"").map(|j| i + j + 1) - }).and_then(|i| { - line[i..].find("\"").map(|j| (i, i + j)) - }).map(|(i, j)| { - &line[i..j] - }) + line.find(attr) + .and_then(|i| line[i..].find('"').map(|j| i + j + 1)) + .and_then(|i| line[i..].find('"').map(|j| (i, i + j))) + .map(|(i, j)| &line[i..j]) } fn collect_lang_features(path: &Path) -> Vec { let mut contents = String::new(); t!(t!(File::open(path)).read_to_string(&mut contents)); - let mut features = Vec::new(); - for line in contents.lines().map(|l| l.trim()) { - if !STATUSES.iter().any(|s| line.starts_with(&format!("({}", s))) { - continue - } - let mut parts = line.split(","); - let status = match &parts.next().unwrap().trim().replace("(", "")[..] { - "active" => "unstable", - "removed" => "unstable", - "accepted" => "stable", - s => panic!("unknown status: {}", s), - }; - let name = parts.next().unwrap().trim().to_owned(); - let since = parts.next().unwrap().trim().replace("\"", ""); - - features.push(Feature { - name: name, - since: since, - status: status.to_owned(), - }); - } - return features + contents.lines() + .filter_map(|line| { + let mut parts = line.trim().split(","); + let level = match parts.next().map(|l| l.trim().trim_left_matches('(')) { + Some("active") => Status::Unstable, + Some("removed") => Status::Unstable, + Some("accepted") => Status::Stable, + _ => return None, + }; + let name = parts.next().unwrap().trim(); + let since = parts.next().unwrap().trim().trim_matches('"'); + Some(Feature { + name: name.to_owned(), + level: level, + since: since.to_owned(), + }) + }) + .collect() } diff --git a/src/tools/tidy/src/main.rs b/src/tools/tidy/src/main.rs index 2839bbded1..cabaee5d06 100644 --- a/src/tools/tidy/src/main.rs +++ b/src/tools/tidy/src/main.rs @@ -36,6 +36,7 @@ mod errors; mod features; mod cargo; mod cargo_lock; +mod pal; fn main() { let path = env::args_os().skip(1).next().expect("need an argument"); @@ -48,6 +49,7 @@ fn main() { cargo::check(&path, &mut bad); features::check(&path, &mut bad); cargo_lock::check(&path, &mut bad); + pal::check(&path, &mut bad); if bad { panic!("some tidy checks failed"); diff --git a/src/tools/tidy/src/pal.rs b/src/tools/tidy/src/pal.rs new file mode 100644 index 0000000000..a5e4e5a4c2 --- /dev/null +++ b/src/tools/tidy/src/pal.rs @@ -0,0 +1,226 @@ +// Copyright 2016 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +//! Tidy check to enforce rules about platform-specific code in std +//! +//! This is intended to maintain existing standards of code +//! organization in hopes that the standard library will continue to +//! be refactored to isolate platform-specific bits, making porting +//! easier; where "standard library" roughly means "all the +//! dependencies of the std and test crates". +//! +//! This generally means placing restrictions on where `cfg(unix)`, +//! `cfg(windows)`, `cfg(target_os)` and `cfg(target_env)` may appear, +//! the basic objective being to isolate platform-specific code to the +//! platform-specific `std::sys` modules, and to the allocation, +//! unwinding, and libc crates. +//! +//! Following are the basic rules, though there are currently +//! exceptions: +//! +//! - core may not have platform-specific code +//! - liballoc_system may have platform-specific code +//! - liballoc_jemalloc may have platform-specific code +//! - libpanic_abort may have platform-specific code +//! - libpanic_unwind may have platform-specific code +//! - libunwind may have platform-specific code +//! - other crates in the std facade may not +//! - std may have platform-specific code in the following places +//! - sys/unix/ +//! - sys/windows/ +//! - os/ +//! +//! `std/sys_common` should _not_ contain platform-specific code. +//! Finally, because std contains tests with platform-specific +//! `ignore` attributes, once the parser encounters `mod tests`, +//! platform-specific cfgs are allowed. Not sure yet how to deal with +//! this in the long term. + +use std::fs::File; +use std::io::Read; +use std::path::Path; +use std::iter::Iterator; + +// Paths that may contain platform-specific code +const EXCEPTION_PATHS: &'static [&'static str] = &[ + // std crates + "src/liballoc_jemalloc", + "src/liballoc_system", + "src/liblibc", + "src/libpanic_abort", + "src/libpanic_unwind", + "src/libunwind", + "src/libstd/sys/", // Platform-specific code for std lives here. + // This has the trailing slash so that sys_common is not excepted. + "src/libstd/os", // Platform-specific public interfaces + "src/rtstartup", // Not sure what to do about this. magic stuff for mingw + + // temporary exceptions + "src/libstd/rtdeps.rs", // Until rustbuild replaces make + "src/libstd/path.rs", + "src/libstd/f32.rs", + "src/libstd/f64.rs", + "src/libstd/sys_common/mod.rs", + "src/libstd/sys_common/net.rs", + "src/libterm", // Not sure how to make this crate portable, but test needs it + "src/libtest", // Probably should defer to unstable std::sys APIs + + // std testing crates, ok for now at least + "src/libcoretest", + + // non-std crates + "src/test", + "src/tools", + "src/librustc", + "src/librustdoc", + "src/libsyntax", + "src/bootstrap", +]; + +pub fn check(path: &Path, bad: &mut bool) { + let ref mut contents = String::new(); + // Sanity check that the complex parsing here works + let ref mut saw_target_arch = false; + let ref mut saw_cfg_bang = false; + super::walk(path, &mut super::filter_dirs, &mut |file| { + let filestr = file.to_string_lossy().replace("\\", "/"); + if !filestr.ends_with(".rs") { return } + + let is_exception_path = EXCEPTION_PATHS.iter().any(|s| filestr.contains(&**s)); + if is_exception_path { return } + + check_cfgs(contents, &file, bad, saw_target_arch, saw_cfg_bang); + }); + + assert!(*saw_target_arch); + assert!(*saw_cfg_bang); +} + +fn check_cfgs(contents: &mut String, file: &Path, + bad: &mut bool, saw_target_arch: &mut bool, saw_cfg_bang: &mut bool) { + contents.truncate(0); + t!(t!(File::open(file), file).read_to_string(contents)); + + // For now it's ok to have platform-specific code after 'mod tests'. + let mod_tests_idx = find_test_mod(contents); + let contents = &contents[..mod_tests_idx]; + // Pull out all "cfg(...)" and "cfg!(...)" strings + let cfgs = parse_cfgs(contents); + + let mut line_numbers: Option> = None; + let mut err = |idx: usize, cfg: &str| { + if line_numbers.is_none() { + line_numbers = Some(contents.match_indices('\n').map(|(i, _)| i).collect()); + } + let line_numbers = line_numbers.as_ref().expect(""); + let line = match line_numbers.binary_search(&idx) { + Ok(_) => unreachable!(), + Err(i) => i + 1 + }; + println!("{}:{}: platform-specific cfg: {}", file.display(), line, cfg); + *bad = true; + }; + + for (idx, cfg) in cfgs.into_iter() { + // Sanity check that the parsing here works + if !*saw_target_arch && cfg.contains("target_arch") { *saw_target_arch = true } + if !*saw_cfg_bang && cfg.contains("cfg!") { *saw_cfg_bang = true } + + let contains_platform_specific_cfg = + cfg.contains("target_os") + || cfg.contains("target_env") + || cfg.contains("target_vendor") + || cfg.contains("unix") + || cfg.contains("windows"); + + if !contains_platform_specific_cfg { continue } + + let preceeded_by_doc_comment = { + let pre_contents = &contents[..idx]; + let pre_newline = pre_contents.rfind('\n'); + let pre_doc_comment = pre_contents.rfind("///"); + match (pre_newline, pre_doc_comment) { + (Some(n), Some(c)) => n < c, + (None, Some(_)) => true, + (_, None) => false, + } + }; + + if preceeded_by_doc_comment { continue } + + err(idx, cfg); + } +} + +fn find_test_mod(contents: &str) -> usize { + if let Some(mod_tests_idx) = contents.find("mod tests") { + // Also capture a previos line indicating "mod tests" in cfg-ed out + let prev_newline_idx = contents[..mod_tests_idx].rfind('\n').unwrap_or(mod_tests_idx); + let prev_newline_idx = contents[..prev_newline_idx].rfind('\n'); + if let Some(nl) = prev_newline_idx { + let prev_line = &contents[nl + 1 .. mod_tests_idx]; + let emcc_cfg = "cfg(all(test, not(target_os"; + if prev_line.contains(emcc_cfg) { + nl + } else { + mod_tests_idx + } + } else { + mod_tests_idx + } + } else { + contents.len() + } +} + +fn parse_cfgs<'a>(contents: &'a str) -> Vec<(usize, &'a str)> { + let candidate_cfgs = contents.match_indices("cfg"); + let candidate_cfg_idxs = candidate_cfgs.map(|(i, _)| i); + // This is puling out the indexes of all "cfg" strings + // that appear to be tokens succeeded by a paren. + let cfgs = candidate_cfg_idxs.filter(|i| { + let pre_idx = i.saturating_sub(*i); + let succeeds_non_ident = !contents.as_bytes().get(pre_idx) + .cloned() + .map(char::from) + .map(char::is_alphanumeric) + .unwrap_or(false); + let contents_after = &contents[*i..]; + let first_paren = contents_after.find('('); + let paren_idx = first_paren.map(|ip| i + ip); + let preceeds_whitespace_and_paren = paren_idx.map(|ip| { + let maybe_space = &contents[*i + "cfg".len() .. ip]; + maybe_space.chars().all(|c| char::is_whitespace(c) || c == '!') + }).unwrap_or(false); + + succeeds_non_ident && preceeds_whitespace_and_paren + }); + + cfgs.map(|i| { + let mut depth = 0; + let contents_from = &contents[i..]; + for (j, byte) in contents_from.bytes().enumerate() { + match byte { + b'(' => { + depth += 1; + } + b')' => { + depth -= 1; + if depth == 0 { + return (i, &contents_from[.. j + 1]); + } + } + _ => { } + } + } + + unreachable!() + }).collect() +} diff --git a/version b/version index 674d989570..3ef8ae8d9b 100644 --- a/version +++ b/version @@ -1 +1 @@ -1.13.0 (2c6933acc 2016-11-07) +1.14.0 (e8a012324 2016-12-16) -- 2.39.2